Add support for non-standard -moz color keyword values.

Closes #15928
This commit is contained in:
Matt Brubeck 2017-03-08 10:17:44 -08:00 committed by Emilio Cobos Álvarez
parent 35028f8f60
commit 16e318d055
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
20 changed files with 188 additions and 58 deletions

View file

@ -426,7 +426,7 @@ fn compute_style_for_animation_step(context: &SharedStyleContext,
};
let computed =
properties::apply_declarations(context.viewport_size(),
properties::apply_declarations(&context.stylist.device,
/* is_root = */ false,
iter,
previous_style,

View file

@ -29,7 +29,7 @@ pub struct Device {
/// NB: The pres context lifetime is tied to the styleset, who owns the
/// stylist, and thus the `Device`, so having a raw pres context pointer
/// here is fine.
pres_context: RawGeckoPresContextOwned,
pub pres_context: RawGeckoPresContextOwned,
default_values: Arc<ComputedValues>,
viewport_override: Option<ViewportConstraints>,
}
@ -497,13 +497,13 @@ impl Expression {
// em units are relative to the initial font-size.
let context = computed::Context {
is_root_element: false,
viewport_size: device.au_viewport_size(),
device: device,
inherited_style: default_values,
layout_parent_style: default_values,
// This cloning business is kind of dumb.... It's because Context
// insists on having an actual ComputedValues inside itself.
style: default_values.clone(),
font_metrics_provider: None
font_metrics_provider: None,
};
let required_value = match self.value {

View file

@ -539,7 +539,7 @@ trait PrivateMatchMethods: TElement {
// Invoke the cascade algorithm.
let values =
Arc::new(cascade(shared_context.viewport_size(),
Arc::new(cascade(&shared_context.stylist.device,
rule_node,
inherited_values,
layout_parent_style,

View file

@ -8,28 +8,24 @@
<%helpers:longhand name="color" need_clone="True" animatable="True"
spec="https://drafts.csswg.org/css-color/#color">
use cssparser::Color as CSSParserColor;
use cssparser::RGBA;
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
use values::specified::{CSSColor, CSSRGBA};
use values::specified::{Color, CSSColor, CSSRGBA};
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T {
match self.0.parsed {
CSSParserColor::RGBA(rgba) => rgba,
CSSParserColor::CurrentColor => context.inherited_style.get_color().clone_color(),
}
self.0.parsed.to_computed_value(context)
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
SpecifiedValue(CSSColor {
parsed: CSSParserColor::RGBA(*computed),
parsed: Color::RGBA(*computed),
authored: None,
})
}

View file

@ -792,7 +792,7 @@ ${helpers.single_keyword("text-align-last",
blur_radius: value.blur_radius.to_computed_value(context),
color: value.color
.as_ref()
.map(|color| color.parsed)
.map(|color| color.to_computed_value(context))
.unwrap_or(cssparser::Color::CurrentColor),
}
}).collect())

View file

@ -10,7 +10,7 @@
additional_methods=[Method("outline_has_nonzero_width", "bool")]) %>
// TODO(pcwalton): `invert`
${helpers.predefined_type("outline-color", "CSSColor", "::cssparser::Color::CurrentColor",
${helpers.predefined_type("outline-color", "CSSColor", "computed::CSSColor::CurrentColor",
initial_specified_value="specified::CSSColor::currentcolor()",
animatable=True, complex_color=True, need_clone=True,
spec="https://drafts.csswg.org/css-ui/#propdef-outline-color")}

View file

@ -224,7 +224,7 @@ ${helpers.single_keyword("text-decoration-style",
${helpers.predefined_type(
"text-decoration-color", "CSSColor",
"::cssparser::Color::CurrentColor",
"computed::CSSColor::CurrentColor",
initial_specified_value="specified::CSSColor::currentcolor()",
complex_color=True,
products="gecko",

View file

@ -21,13 +21,13 @@ use app_units::Au;
use cssparser::{Parser, TokenSerializationType};
use error_reporting::ParseErrorReporter;
#[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D;
use euclid::size::Size2D;
use computed_values;
use font_metrics::FontMetricsProvider;
#[cfg(feature = "gecko")] use gecko_bindings::bindings;
#[cfg(feature = "gecko")] use gecko_bindings::structs::{self, nsCSSPropertyID};
#[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
use logical_geometry::WritingMode;
use media_queries::Device;
use parser::{Parse, ParserContext, ParserContextExtraData};
use properties::animated_properties::TransitionProperty;
#[cfg(feature = "servo")] use servo_config::prefs::PREFS;
@ -1793,7 +1793,7 @@ bitflags! {
///
/// The arguments are:
///
/// * `viewport_size`: The size of the initial viewport.
/// * `device`: Used to get the initial viewport and other external state.
///
/// * `rule_node`: The rule node in the tree that represent the CSS rules that
/// matched.
@ -1803,7 +1803,7 @@ bitflags! {
/// Returns the computed values.
/// * `flags`: Various flags.
///
pub fn cascade(viewport_size: Size2D<Au>,
pub fn cascade(device: &Device,
rule_node: &StrongRuleNode,
parent_style: Option<<&ComputedValues>,
layout_parent_style: Option<<&ComputedValues>,
@ -1836,7 +1836,7 @@ pub fn cascade(viewport_size: Size2D<Au>,
})
})
};
apply_declarations(viewport_size,
apply_declarations(device,
is_root_element,
iter_declarations,
inherited_style,
@ -1850,7 +1850,7 @@ pub fn cascade(viewport_size: Size2D<Au>,
/// NOTE: This function expects the declaration with more priority to appear
/// first.
pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
pub fn apply_declarations<'a, F, I>(device: &Device,
is_root_element: bool,
iter_declarations: F,
inherited_style: &ComputedValues,
@ -1905,7 +1905,7 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
let mut context = computed::Context {
is_root_element: is_root_element,
viewport_size: viewport_size,
device: device,
inherited_style: inherited_style,
layout_parent_style: layout_parent_style,
style: starting_style,

View file

@ -2,9 +2,8 @@
* 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;
use style_traits::ToCss;
use values::specified::{BorderStyle, CSSColor};
use values::specified::{BorderStyle, Color, CSSColor};
use std::fmt;
#[allow(missing_docs)]

View file

@ -10,13 +10,12 @@
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration">
% if product == "gecko" or data.testing:
use cssparser::Color as CSSParserColor;
use values::specified;
use properties::longhands::{text_decoration_line, text_decoration_style, text_decoration_color};
% else:
use properties::longhands::text_decoration_line;
% endif
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
% if product == "gecko" or data.testing:
let (mut line, mut style, mut color, mut any) = (None, None, None, false);
@ -71,7 +70,7 @@
self.text_decoration_style.to_css(dest)?;
}
if self.text_decoration_color.parsed != CSSParserColor::CurrentColor {
if self.text_decoration_color.parsed != specified::Color::CurrentColor {
dest.write_str(" ")?;
self.text_decoration_color.to_css(dest)?;
}

View file

@ -128,7 +128,7 @@ impl Expression {
let value = viewport_size.width;
match self.0 {
ExpressionKind::Width(ref range) => {
match range.to_computed_range(viewport_size, device.default_values()) {
match range.to_computed_range(device) {
Range::Min(ref width) => { value >= *width },
Range::Max(ref width) => { value <= *width },
Range::Eq(ref width) => { value == *width },
@ -170,15 +170,13 @@ pub enum Range<T> {
}
impl Range<specified::Length> {
fn to_computed_range(&self,
viewport_size: Size2D<Au>,
default_values: &ComputedValues)
-> Range<Au> {
fn to_computed_range(&self, device: &Device) -> Range<Au> {
let default_values = device.default_values();
// http://dev.w3.org/csswg/mediaqueries3/#units
// em units are relative to the initial font-size.
let context = computed::Context {
is_root_element: false,
viewport_size: viewport_size,
device: device,
inherited_style: default_values,
layout_parent_style: default_values,
// This cloning business is kind of dumb.... It's because Context

View file

@ -325,7 +325,7 @@ impl Stylist {
// the actual used value, and the computed value of it would need
// blockification.
let computed =
properties::cascade(self.device.au_viewport_size(),
properties::cascade(&self.device,
&rule_node,
parent.map(|p| &**p),
parent.map(|p| &**p),
@ -410,7 +410,7 @@ impl Stylist {
// (tl;dr: It doesn't apply for replaced elements and such, but the
// computed value is still "contents").
let computed =
properties::cascade(self.device.au_viewport_size(),
properties::cascade(&self.device,
&rule_node,
Some(&**parent),
Some(&**parent),

View file

@ -250,7 +250,7 @@ impl ToComputedValue for specified::ColorStop {
#[inline]
fn to_computed_value(&self, context: &Context) -> ColorStop {
ColorStop {
color: self.color.parsed,
color: self.color.to_computed_value(context),
position: match self.position {
None => None,
Some(ref value) => Some(value.to_computed_value(context)),

View file

@ -12,7 +12,6 @@ use super::{Number, ToComputedValue, Context};
use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
use values::specified::length::{FontRelativeLength, ViewportPercentageLength};
pub use cssparser::Color as CSSColor;
pub use super::image::{EndingShape as GradientShape, Gradient, GradientKind, Image};
pub use super::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};

View file

@ -7,6 +7,7 @@
use app_units::Au;
use euclid::size::Size2D;
use font_metrics::FontMetricsProvider;
use media_queries::Device;
use properties::ComputedValues;
use std::fmt;
use style_traits::ToCss;
@ -37,8 +38,8 @@ pub struct Context<'a> {
/// Whether the current element is the root element.
pub is_root_element: bool,
/// The current viewport size.
pub viewport_size: Size2D<Au>,
/// The Device holds the viewport and other external state.
pub device: &'a Device,
/// The style we're inheriting from.
pub inherited_style: &'a ComputedValues,
@ -65,7 +66,7 @@ impl<'a> Context<'a> {
/// Whether the current element is the root element.
pub fn is_root_element(&self) -> bool { self.is_root_element }
/// The current viewport size.
pub fn viewport_size(&self) -> Size2D<Au> { self.viewport_size }
pub fn viewport_size(&self) -> Size2D<Au> { self.device.au_viewport_size() }
/// The style we're inheriting from.
pub fn inherited_style(&self) -> &ComputedValues { &self.inherited_style }
/// The current style. Note that only "eager" properties should be accessed
@ -113,18 +114,65 @@ impl<T> ToComputedValue for T
}
}
impl ToComputedValue for specified::Color {
type ComputedValue = RGBA;
#[cfg(not(feature = "gecko"))]
fn to_computed_value(&self, context: &Context) -> RGBA {
match *self {
specified::Color::RGBA(rgba) => rgba,
specified::Color::CurrentColor => context.inherited_style.get_color().clone_color(),
}
}
#[cfg(feature = "gecko")]
fn to_computed_value(&self, context: &Context) -> RGBA {
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 {
specified::Color::RGBA(rgba) => rgba,
specified::Color::CurrentColor => context.inherited_style.get_color().clone_color(),
specified::Color::MozDefaultColor => to_rgba(pres_context.mDefaultColor),
specified::Color::MozDefaultBackgroundColor => to_rgba(pres_context.mBackgroundColor),
specified::Color::MozHyperlinktext => to_rgba(pres_context.mLinkColor),
specified::Color::MozActiveHyperlinktext => to_rgba(pres_context.mActiveLinkColor),
specified::Color::MozVisitedHyperlinktext => to_rgba(pres_context.mVisitedLinkColor),
}
}
fn from_computed_value(computed: &RGBA) -> Self {
specified::Color::RGBA(*computed)
}
}
impl ToComputedValue for specified::CSSColor {
type ComputedValue = CSSColor;
#[cfg(not(feature = "gecko"))]
#[inline]
fn to_computed_value(&self, _context: &Context) -> CSSColor {
self.parsed
}
#[cfg(feature = "gecko")]
#[inline]
fn to_computed_value(&self, context: &Context) -> CSSColor {
match self.parsed {
specified::Color::RGBA(rgba) => CSSColor::RGBA(rgba),
specified::Color::CurrentColor => CSSColor::CurrentColor,
// Resolve non-standard -moz keywords to RGBA:
non_standard => CSSColor::RGBA(non_standard.to_computed_value(context)),
}
}
#[inline]
fn from_computed_value(computed: &CSSColor) -> Self {
specified::CSSColor {
parsed: *computed,
parsed: match *computed {
CSSColor::RGBA(rgba) => specified::Color::RGBA(rgba),
CSSColor::CurrentColor => specified::Color::CurrentColor,
},
authored: None,
}
}

View file

@ -0,0 +1,90 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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
#[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};
impl Parse for Color {
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Color::parse(input)
}
}
}
#[cfg(feature = "gecko")]
mod gecko {
use cssparser::{Color as CSSParserColor, Parser, RGBA};
use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
/// 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),
/// -moz-default-color
MozDefaultColor,
/// -moz-default-background-color
MozDefaultBackgroundColor,
/// -moz-hyperlinktext
MozHyperlinktext,
/// -moz-activehyperlinktext
MozActiveHyperlinktext,
/// -moz-visitedhyperlinktext
MozVisitedHyperlinktext,
}
no_viewport_percentage!(Color);
impl Parse for Color {
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if let Ok(value) = input.try(CSSParserColor::parse) {
match value {
CSSParserColor::CurrentColor => Ok(Color::CurrentColor),
CSSParserColor::RGBA(x) => Ok(Color::RGBA(x)),
}
} else {
let ident = input.expect_ident()?;
match_ignore_ascii_case! { &ident,
"-moz-default-color" => Ok(Color::MozDefaultColor),
"-moz-default-background-color" => Ok(Color::MozDefaultBackgroundColor),
"-moz-hyperlinktext" => Ok(Color::MozHyperlinktext),
"-moz-activehyperlinktext" => Ok(Color::MozActiveHyperlinktext),
"-moz-visitedhyperlinktext" => Ok(Color::MozVisitedHyperlinktext),
_ => 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),
// Non-standard values:
Color::MozDefaultColor => dest.write_str("-moz-default-color"),
Color::MozDefaultBackgroundColor => dest.write_str("-moz-default-background-color"),
Color::MozHyperlinktext => dest.write_str("-moz-hyperlinktext"),
Color::MozActiveHyperlinktext => dest.write_str("-moz-activehyperlinktext"),
Color::MozVisitedHyperlinktext => dest.write_str("-moz-visitedhyperlinktext"),
}
}
}
}

View file

@ -18,11 +18,12 @@ use std::fmt;
use std::ops::Mul;
use style_traits::ToCss;
use super::{Auto, CSSFloat, HasViewportPercentage, Either, None_};
use super::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
use super::computed::Shadow as ComputedShadow;
use super::computed::{ComputedValueAsSpecified, Context};
use super::computed::{Shadow as ComputedShadow, ToComputedValue};
#[cfg(feature = "gecko")]
pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
pub use self::color::Color;
pub use self::grid::{GridLine, TrackKeyword};
pub use self::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
pub use self::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword};
@ -36,6 +37,7 @@ pub use self::position::{HorizontalPosition, Position, VerticalPosition};
#[cfg(feature = "gecko")]
pub mod align;
pub mod basic_shape;
pub mod color;
pub mod grid;
pub mod image;
pub mod length;
@ -48,12 +50,12 @@ no_viewport_percentage!(i32); // For PropertyDeclaration::Order
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct CSSColor {
pub parsed: cssparser::Color,
pub parsed: Color,
pub authored: Option<Box<str>>,
}
impl Parse for CSSColor {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
let start_position = input.position();
let authored = match input.next() {
Ok(Token::Ident(s)) => Some(s.into_owned().into_boxed_str()),
@ -61,7 +63,7 @@ impl Parse for CSSColor {
};
input.reset(start_position);
Ok(CSSColor {
parsed: try!(cssparser::Color::parse(input)),
parsed: try!(Parse::parse(context, input)),
authored: authored,
})
}
@ -83,7 +85,7 @@ impl CSSColor {
/// Returns currentcolor value.
pub fn currentcolor() -> CSSColor {
CSSColor {
parsed: cssparser::Color::CurrentColor,
parsed: Color::CurrentColor,
authored: None,
}
}
@ -92,7 +94,7 @@ impl CSSColor {
/// Returns transparent value.
pub fn transparent() -> CSSColor {
CSSColor {
parsed: cssparser::Color::RGBA(cssparser::RGBA::transparent()),
parsed: Color::RGBA(cssparser::RGBA::transparent()),
// This should probably be "transparent", but maybe it doesn't matter.
authored: None,
}
@ -616,7 +618,7 @@ impl ToComputedValue for Shadow {
spread_radius: self.spread_radius.to_computed_value(context),
color: self.color
.as_ref()
.map(|color| color.parsed)
.map(|color| color.to_computed_value(context))
.unwrap_or(cssparser::Color::CurrentColor),
inset: self.inset,
}

View file

@ -687,7 +687,7 @@ impl MaybeNew for ViewportConstraints {
// TODO(emilio): Stop cloning `ComputedValues` around!
let context = Context {
is_root_element: false,
viewport_size: initial_viewport,
device: device,
inherited_style: device.default_values(),
layout_parent_style: device.default_values(),
style: device.default_values().clone(),

View file

@ -1173,9 +1173,8 @@ pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(declarations:
pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations:
RawServoDeclarationBlockBorrowed,
property: nsCSSPropertyID) {
use cssparser::Color;
use style::properties::{DeclaredValue, PropertyDeclaration, LonghandId};
use style::values::specified::CSSColor;
use style::values::specified::{Color, CSSColor};
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property);
@ -1195,11 +1194,10 @@ pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations:
RawServoDeclarationBlockBorrowed,
property: nsCSSPropertyID,
value: structs::nscolor) {
use cssparser::Color;
use style::gecko::values::convert_nscolor_to_rgba;
use style::properties::{DeclaredValue, PropertyDeclaration, LonghandId};
use style::properties::longhands;
use style::values::specified::CSSColor;
use style::values::specified::{Color, CSSColor};
let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
let long = get_longhand_from_id!(property);
@ -1444,7 +1442,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis
let context = Context {
is_root_element: false,
viewport_size: data.stylist.device.au_viewport_size(),
device: &data.stylist.device,
inherited_style: parent_style.unwrap_or(default_values),
layout_parent_style: parent_style.unwrap_or(default_values),
style: (**style).clone(),

View file

@ -2,11 +2,11 @@
* 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 app_units::Au;
use cssparser::Parser;
use euclid::size::Size2D;
use euclid::size::TypedSize2D;
use media_queries::CSSErrorReporterTest;
use std::f32::consts::PI;
use style::media_queries::{Device, MediaType};
use style::parser::ParserContext;
use style::properties::ComputedValues;
use style::stylesheets::Origin;
@ -43,11 +43,12 @@ fn test_linear_gradient() {
// AngleOrCorner::None should become AngleOrCorner::Angle(Angle(PI)) when parsed
// Note that Angle(PI) is correct for top-to-bottom rendering, whereas Angle(0) would render bottom-to-top.
// ref: https://developer.mozilla.org/en-US/docs/Web/CSS/angle
let container = Size2D::new(Au::default(), Au::default());
let viewport_size = TypedSize2D::new(0., 0.);
let initial_style = ComputedValues::initial_values();
let device = Device::new(MediaType::Screen, viewport_size);
let specified_context = Context {
is_root_element: true,
viewport_size: container,
device: &device,
inherited_style: initial_style,
layout_parent_style: initial_style,
style: initial_style.clone(),