aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-10-16 04:49:33 -0500
committerGitHub <noreply@github.com>2017-10-16 04:49:33 -0500
commit1e351ef8c478de507c6ee7b65eeff7524d73a4c9 (patch)
tree0f460841dbe50c97d5259cc92a83ce16d1cb9ea8
parenta759ded65d965b54c535c74d460f60a782e51487 (diff)
parent46695336e8c38ae0dd9d3362f0700b2ad724886e (diff)
downloadservo-1e351ef8c478de507c6ee7b65eeff7524d73a4c9.tar.gz
servo-1e351ef8c478de507c6ee7b65eeff7524d73a4c9.zip
Auto merge of #18891 - heycam:color-refactor, r=upsuper
style: add FFI functions for color parsing Servo side of https://bugzilla.mozilla.org/show_bug.cgi?id=1408312, reviewed there by Xidorn. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18891) <!-- Reviewable:end -->
-rw-r--r--components/style/values/specified/color.rs157
-rw-r--r--ports/geckolib/glue.rs66
2 files changed, 155 insertions, 68 deletions
diff --git a/components/style/values/specified/color.rs b/components/style/values/specified/color.rs
index bee0daecfea..aae2674803e 100644
--- a/components/style/values/specified/color.rs
+++ b/components/style/values/specified/color.rs
@@ -67,42 +67,7 @@ impl From<RGBA> for Color {
impl Parse for Color {
fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
- // Currently we only store authored value for color keywords,
- // because all browsers serialize those values as keywords for
- // specified value.
- let start = input.state();
- let authored = match input.next() {
- Ok(&Token::Ident(ref s)) => Some(s.to_lowercase().into_boxed_str()),
- _ => None,
- };
- input.reset(&start);
- match input.try(CSSParserColor::parse) {
- Ok(value) =>
- Ok(match value {
- CSSParserColor::CurrentColor => Color::CurrentColor,
- CSSParserColor::RGBA(rgba) => Color::Numeric {
- parsed: rgba,
- authored: authored,
- },
- }),
- Err(e) => {
- #[cfg(feature = "gecko")] {
- if let Ok(system) = input.try(SystemColor::parse) {
- return Ok(Color::System(system));
- } else if let Ok(c) = gecko::SpecialColorKeyword::parse(input) {
- return Ok(Color::Special(c));
- }
- }
- match e {
- BasicParseError { kind: BasicParseErrorKind::UnexpectedToken(t), location } => {
- Err(location.new_custom_error(
- StyleParseErrorKind::ValueError(ValueParseErrorKind::InvalidColor(t))
- ))
- }
- e => Err(e.into())
- }
- }
- }
+ Color::parse_color(input)
}
}
@@ -244,6 +209,46 @@ impl Color {
_ => true,
}
}
+
+ /// Parse a <color> value.
+ pub fn parse_color<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
+ // Currently we only store authored value for color keywords,
+ // because all browsers serialize those values as keywords for
+ // specified value.
+ let start = input.state();
+ let authored = match input.next() {
+ Ok(&Token::Ident(ref s)) => Some(s.to_lowercase().into_boxed_str()),
+ _ => None,
+ };
+ input.reset(&start);
+ match input.try(CSSParserColor::parse) {
+ Ok(value) =>
+ Ok(match value {
+ CSSParserColor::CurrentColor => Color::CurrentColor,
+ CSSParserColor::RGBA(rgba) => Color::Numeric {
+ parsed: rgba,
+ authored: authored,
+ },
+ }),
+ Err(e) => {
+ #[cfg(feature = "gecko")] {
+ if let Ok(system) = input.try(SystemColor::parse) {
+ return Ok(Color::System(system));
+ } else if let Ok(c) = gecko::SpecialColorKeyword::parse(input) {
+ return Ok(Color::Special(c));
+ }
+ }
+ match e {
+ BasicParseError { kind: BasicParseErrorKind::UnexpectedToken(t), location } => {
+ Err(location.new_custom_error(
+ StyleParseErrorKind::ValueError(ValueParseErrorKind::InvalidColor(t))
+ ))
+ }
+ e => Err(e.into())
+ }
+ }
+ }
+ }
}
#[cfg(feature = "gecko")]
@@ -252,53 +257,71 @@ fn convert_nscolor_to_computedcolor(color: nscolor) -> ComputedColor {
ComputedColor::rgba(convert_nscolor_to_rgba(color))
}
-impl ToComputedValue for Color {
- type ComputedValue = ComputedColor;
-
- fn to_computed_value(&self, context: &Context) -> ComputedColor {
+impl Color {
+ /// Converts this Color into a ComputedColor.
+ ///
+ /// If `context` is `None`, and the specified color requires data from
+ /// the context to resolve, then `None` is returned.
+ pub fn to_computed_color(
+ &self,
+ _context: Option<&Context>,
+ ) -> Option<ComputedColor> {
match *self {
Color::CurrentColor => {
- if let Some(longhand) = context.for_non_inherited_property {
- if longhand.stores_complex_colors_lossily() {
- context.rule_cache_conditions.borrow_mut()
- .set_uncacheable();
- }
- }
- ComputedColor::currentcolor()
+ Some(ComputedColor::currentcolor())
+ }
+ Color::Numeric { ref parsed, .. } => {
+ Some(ComputedColor::rgba(*parsed))
}
- Color::Numeric { ref parsed, .. } => ComputedColor::rgba(*parsed),
Color::Complex(ref complex) => {
- if complex.foreground_ratio != 0 {
- if let Some(longhand) = context.for_non_inherited_property {
- if longhand.stores_complex_colors_lossily() {
- context.rule_cache_conditions.borrow_mut()
- .set_uncacheable();
- }
- }
- }
- *complex
+ Some(*complex)
}
#[cfg(feature = "gecko")]
- Color::System(system) =>
- convert_nscolor_to_computedcolor(system.to_computed_value(context)),
+ Color::System(system) => {
+ _context.map(|context| {
+ convert_nscolor_to_computedcolor(
+ system.to_computed_value(context)
+ )
+ })
+ }
#[cfg(feature = "gecko")]
Color::Special(special) => {
use self::gecko::SpecialColorKeyword as Keyword;
- let pres_context = context.device().pres_context();
- convert_nscolor_to_computedcolor(match special {
- Keyword::MozDefaultColor => pres_context.mDefaultColor,
- Keyword::MozDefaultBackgroundColor => pres_context.mBackgroundColor,
- Keyword::MozHyperlinktext => pres_context.mLinkColor,
- Keyword::MozActiveHyperlinktext => pres_context.mActiveLinkColor,
- Keyword::MozVisitedHyperlinktext => pres_context.mVisitedLinkColor,
+ _context.map(|context| {
+ let pres_context = context.device().pres_context();
+ convert_nscolor_to_computedcolor(match special {
+ Keyword::MozDefaultColor => pres_context.mDefaultColor,
+ Keyword::MozDefaultBackgroundColor => pres_context.mBackgroundColor,
+ Keyword::MozHyperlinktext => pres_context.mLinkColor,
+ Keyword::MozActiveHyperlinktext => pres_context.mActiveLinkColor,
+ Keyword::MozVisitedHyperlinktext => pres_context.mVisitedLinkColor,
+ })
})
}
#[cfg(feature = "gecko")]
Color::InheritFromBodyQuirk => {
- ComputedColor::rgba(context.device().body_text_color())
+ _context.map(|context| {
+ ComputedColor::rgba(context.device().body_text_color())
+ })
},
}
}
+}
+
+impl ToComputedValue for Color {
+ type ComputedValue = ComputedColor;
+
+ fn to_computed_value(&self, context: &Context) -> ComputedColor {
+ let result = self.to_computed_color(Some(context)).unwrap();
+ if result.foreground_ratio != 0 {
+ if let Some(longhand) = context.for_non_inherited_property {
+ if longhand.stores_complex_colors_lossily() {
+ context.rule_cache_conditions.borrow_mut().set_uncacheable();
+ }
+ }
+ }
+ result
+ }
fn from_computed_value(computed: &ComputedColor) -> Self {
if computed.is_numeric() {
diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs
index 509d869c625..9e7c2f22f2d 100644
--- a/ports/geckolib/glue.rs
+++ b/ports/geckolib/glue.rs
@@ -44,7 +44,7 @@ use style::gecko_bindings::bindings::{RawServoMediaRule, RawServoMediaRuleBorrow
use style::gecko_bindings::bindings::{RawServoNamespaceRule, RawServoNamespaceRuleBorrowed};
use style::gecko_bindings::bindings::{RawServoPageRule, RawServoPageRuleBorrowed};
use style::gecko_bindings::bindings::{RawServoSelectorListBorrowed, RawServoSelectorListOwned};
-use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSetOwned};
+use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSetBorrowedOrNull, RawServoStyleSetOwned};
use style::gecko_bindings::bindings::{RawServoStyleSheetContentsBorrowed, ServoComputedDataBorrowed};
use style::gecko_bindings::bindings::{RawServoStyleSheetContentsStrong, ServoStyleContextBorrowed};
use style::gecko_bindings::bindings::{RawServoSupportsRule, RawServoSupportsRuleBorrowed};
@@ -145,6 +145,7 @@ use style::values::{CustomIdent, KeyframesName};
use style::values::animated::{Animate, Procedure, ToAnimatedZero};
use style::values::computed::{Context, ToComputedValue};
use style::values::distance::ComputeSquaredDistance;
+use style::values::specified;
use style_traits::{PARSING_MODE_DEFAULT, ToCss};
use super::error_reporter::ErrorReporter;
use super::stylesheet_loader::StylesheetLoader;
@@ -4206,3 +4207,66 @@ pub unsafe extern "C" fn Servo_SelectorList_Parse(
pub unsafe extern "C" fn Servo_SelectorList_Drop(list: RawServoSelectorListOwned) {
let _ = list.into_box::<::selectors::SelectorList<SelectorImpl>>();
}
+
+fn parse_color(value: &str) -> Result<specified::Color, ()> {
+ let mut input = ParserInput::new(value);
+ let mut parser = Parser::new(&mut input);
+ parser.parse_entirely(specified::Color::parse_color).map_err(|_| ())
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_IsValidCSSColor(
+ value: *const nsAString,
+) -> bool {
+ let value = unsafe { (*value).to_string() };
+ parse_color(&value).is_ok()
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_ComputeColor(
+ raw_data: RawServoStyleSetBorrowedOrNull,
+ current_color: structs::nscolor,
+ value: *const nsAString,
+ result_color: *mut structs::nscolor,
+) -> bool {
+ use style::gecko;
+
+ let current_color = gecko::values::convert_nscolor_to_rgba(current_color);
+ let value = unsafe { (*value).to_string() };
+ let result_color = unsafe { result_color.as_mut().unwrap() };
+
+ match parse_color(&value) {
+ Ok(specified_color) => {
+ let computed_color = match raw_data {
+ Some(raw_data) => {
+ let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
+ let metrics = get_metrics_provider_for_product();
+ let mut conditions = Default::default();
+ let context = create_context(
+ &data,
+ &metrics,
+ data.stylist.device().default_computed_values(),
+ /* parent_style = */ None,
+ /* pseudo = */ None,
+ /* for_smil_animation = */ false,
+ &mut conditions,
+ );
+ specified_color.to_computed_color(Some(&context))
+ }
+ None => {
+ specified_color.to_computed_color(None)
+ }
+ };
+
+ match computed_color {
+ Some(computed_color) => {
+ let rgba = computed_color.to_rgba(current_color);
+ *result_color = gecko::values::convert_rgba_to_nscolor(&rgba);
+ true
+ }
+ None => false,
+ }
+ }
+ Err(_) => false,
+ }
+}