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

Move specified color types into specified::color mod.

  • Loading branch information
upsuper committed Jun 8, 2017
commit a7dda6115896c173277c044527d277a45168b08e
@@ -2,7 +2,15 @@
* 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/. */

//! Non-standard CSS color values
//! Specified color values.

use cssparser::{self, Parser, Token};
use itoa;
use parser::{ParserContext, Parse};
use std::fmt;
use std::io::Write;
use style_traits::ToCss;
use super::AllowQuirks;

#[cfg(not(feature = "gecko"))] pub use self::servo::Color;
#[cfg(feature = "gecko")] pub use self::gecko::Color;
@@ -101,3 +109,144 @@ mod gecko {
}
}
}

#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct CSSColor {
pub parsed: Color,
pub authored: Option<Box<str>>,
}

impl Parse for CSSColor {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Self::parse_quirky(context, input, AllowQuirks::No)
}
}

impl CSSColor {
/// Parse a color, with quirks.
///
/// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
pub fn parse_quirky(context: &ParserContext,
input: &mut Parser,
allow_quirks: AllowQuirks)
-> Result<Self, ()> {
let start_position = input.position();
let authored = match input.next() {
Ok(Token::Ident(s)) => Some(s.into_owned().into_boxed_str()),
_ => None,
};
input.reset(start_position);
if let Ok(parsed) = input.try(|i| Parse::parse(context, i)) {
return Ok(CSSColor {
parsed: parsed,
authored: authored,
});
}
if !allow_quirks.allowed(context.quirks_mode) {
return Err(());
}
let (number, dimension) = match input.next()? {
Token::Number(number) => {
(number, None)
},
Token::Dimension(number, dimension) => {
(number, Some(dimension))
},
Token::Ident(ident) => {
if ident.len() != 3 && ident.len() != 6 {
return Err(());
}
return cssparser::Color::parse_hash(ident.as_bytes()).map(|color| {
Self {
parsed: color.into(),
authored: None
}
});
}
_ => {
return Err(());
},
};
let value = number.int_value.ok_or(())?;
if value < 0 {
return Err(());
}
let length = if value <= 9 {
1
} else if value <= 99 {
2
} else if value <= 999 {
3
} else if value <= 9999 {
4
} else if value <= 99999 {
5
} else if value <= 999999 {
6
} else {
return Err(())
};
let total = length + dimension.as_ref().map_or(0, |d| d.len());
if total > 6 {
return Err(());
}
let mut serialization = [b'0'; 6];
let space_padding = 6 - total;
let mut written = space_padding;
written += itoa::write(&mut serialization[written..], value).unwrap();
if let Some(dimension) = dimension {
written += (&mut serialization[written..]).write(dimension.as_bytes()).unwrap();
}
debug_assert!(written == 6);
Ok(CSSColor {
parsed: cssparser::Color::parse_hash(&serialization).map(From::from)?,
authored: None,
})
}

/// Returns false if the color is completely transparent, and
/// true otherwise.
pub fn is_non_transparent(&self) -> bool {
match self.parsed {
Color::RGBA(rgba) if rgba.alpha == 0 => false,
_ => true,
}
}
}

no_viewport_percentage!(CSSColor);

impl ToCss for CSSColor {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match self.authored {
Some(ref s) => dest.write_str(s),
None => self.parsed.to_css(dest),
}
}
}

impl From<Color> for CSSColor {
fn from(color: Color) -> Self {
CSSColor {
parsed: color,
authored: None,
}
}
}

impl CSSColor {
#[inline]
/// Returns currentcolor value.
pub fn currentcolor() -> CSSColor {
Color::CurrentColor.into()
}

#[inline]
/// Returns transparent value.
pub fn transparent() -> CSSColor {
// We should probably set authored to "transparent", but maybe it doesn't matter.
Color::RGBA(cssparser::RGBA::transparent()).into()
}
}
@@ -9,14 +9,12 @@
use Namespace;
use context::QuirksMode;
use cssparser::{self, Parser, Token, serialize_identifier};
use itoa;
use parser::{ParserContext, Parse};
use self::grid::TrackSizeOrRepeat;
use self::url::SpecifiedUrl;
use std::ascii::AsciiExt;
use std::f32;
use std::fmt;
use std::io::Write;
use style_traits::ToCss;
use style_traits::values::specified::AllowedNumericType;
use super::{Auto, CSSFloat, CSSInteger, Either, None_};
@@ -33,7 +31,7 @@ pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, Justify
pub use self::background::BackgroundSize;
pub use self::border::{BorderCornerRadius, BorderImageSlice, BorderImageWidth};
pub use self::border::{BorderImageSideWidth, BorderRadius, BorderSideWidth};
pub use self::color::Color;
pub use self::color::{CSSColor, Color};
pub use self::rect::LengthOrNumberRect;
#[cfg(feature = "gecko")]
pub use self::gecko::ScrollSnapPoint;
@@ -92,147 +90,6 @@ impl ComputedValueAsSpecified for SpecifiedUrl {}
no_viewport_percentage!(SpecifiedUrl);
}

#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct CSSColor {
pub parsed: Color,
pub authored: Option<Box<str>>,
}

impl Parse for CSSColor {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Self::parse_quirky(context, input, AllowQuirks::No)
}
}

impl CSSColor {
/// Parse a color, with quirks.
///
/// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
pub fn parse_quirky(context: &ParserContext,
input: &mut Parser,
allow_quirks: AllowQuirks)
-> Result<Self, ()> {
let start_position = input.position();
let authored = match input.next() {
Ok(Token::Ident(s)) => Some(s.into_owned().into_boxed_str()),
_ => None,
};
input.reset(start_position);
if let Ok(parsed) = input.try(|i| Parse::parse(context, i)) {
return Ok(CSSColor {
parsed: parsed,
authored: authored,
});
}
if !allow_quirks.allowed(context.quirks_mode) {
return Err(());
}
let (number, dimension) = match input.next()? {
Token::Number(number) => {
(number, None)
},
Token::Dimension(number, dimension) => {
(number, Some(dimension))
},
Token::Ident(ident) => {
if ident.len() != 3 && ident.len() != 6 {
return Err(());
}
return cssparser::Color::parse_hash(ident.as_bytes()).map(|color| {
Self {
parsed: color.into(),
authored: None
}
});
}
_ => {
return Err(());
},
};
let value = number.int_value.ok_or(())?;
if value < 0 {
return Err(());
}
let length = if value <= 9 {
1
} else if value <= 99 {
2
} else if value <= 999 {
3
} else if value <= 9999 {
4
} else if value <= 99999 {
5
} else if value <= 999999 {
6
} else {
return Err(())
};
let total = length + dimension.as_ref().map_or(0, |d| d.len());
if total > 6 {
return Err(());
}
let mut serialization = [b'0'; 6];
let space_padding = 6 - total;
let mut written = space_padding;
written += itoa::write(&mut serialization[written..], value).unwrap();
if let Some(dimension) = dimension {
written += (&mut serialization[written..]).write(dimension.as_bytes()).unwrap();
}
debug_assert!(written == 6);
Ok(CSSColor {
parsed: cssparser::Color::parse_hash(&serialization).map(From::from)?,
authored: None,
})
}

/// Returns false if the color is completely transparent, and
/// true otherwise.
pub fn is_non_transparent(&self) -> bool {
match self.parsed {
Color::RGBA(rgba) if rgba.alpha == 0 => false,
_ => true,
}
}
}

no_viewport_percentage!(CSSColor);

impl ToCss for CSSColor {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match self.authored {
Some(ref s) => dest.write_str(s),
None => self.parsed.to_css(dest),
}
}
}

impl From<Color> for CSSColor {
fn from(color: Color) -> Self {
CSSColor {
parsed: color,
authored: None,
}
}
}

impl CSSColor {
#[inline]
/// Returns currentcolor value.
pub fn currentcolor() -> CSSColor {
Color::CurrentColor.into()
}

#[inline]
/// Returns transparent value.
pub fn transparent() -> CSSColor {
// We should probably set authored to "transparent", but maybe it doesn't matter.
Color::RGBA(cssparser::RGBA::transparent()).into()
}
}

/// Parse an `<integer>` value, handling `calc()` correctly.
pub fn parse_integer(context: &ParserContext, input: &mut Parser) -> Result<Integer, ()> {
match try!(input.next()) {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.