mirror of
https://github.com/servo/servo.git
synced 2025-07-03 05:23:38 +01:00
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 -->
This commit is contained in:
commit
1e351ef8c4
2 changed files with 155 additions and 68 deletions
|
@ -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,38 +257,37 @@ 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();
|
||||
Some(ComputedColor::currentcolor())
|
||||
}
|
||||
Color::Numeric { ref parsed, .. } => {
|
||||
Some(ComputedColor::rgba(*parsed))
|
||||
}
|
||||
ComputedColor::currentcolor()
|
||||
}
|
||||
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;
|
||||
_context.map(|context| {
|
||||
let pres_context = context.device().pres_context();
|
||||
convert_nscolor_to_computedcolor(match special {
|
||||
Keyword::MozDefaultColor => pres_context.mDefaultColor,
|
||||
|
@ -292,13 +296,32 @@ impl ToComputedValue for Color {
|
|||
Keyword::MozActiveHyperlinktext => pres_context.mActiveLinkColor,
|
||||
Keyword::MozVisitedHyperlinktext => pres_context.mVisitedLinkColor,
|
||||
})
|
||||
})
|
||||
}
|
||||
#[cfg(feature = "gecko")]
|
||||
Color::InheritFromBodyQuirk => {
|
||||
_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() {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue