aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-06-07 21:03:52 -0700
committerGitHub <noreply@github.com>2017-06-07 21:03:52 -0700
commit24e944ad94816e607e833e34095c4f8b8136df4c (patch)
treeaa3f07d3a7c66a4cb065f9030b29fc3fd5f71e39
parentc0f3ec87806a0d718d7f9ef1ccb912c78fc482d2 (diff)
parent5c643adb9831ef9c59b96da2eb6349554afa2441 (diff)
downloadservo-24e944ad94816e607e833e34095c4f8b8136df4c.tar.gz
servo-24e944ad94816e607e833e34095c4f8b8136df4c.zip
Auto merge of #17219 - upsuper:currentcolor, r=Manishearth,birtles
Support interpolation between currentcolor and numeric color This is the Servo side change of [bug 1345709](https://bugzilla.mozilla.org/show_bug.cgi?id=1345709). <!-- 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/17219) <!-- Reviewable:end -->
-rw-r--r--Cargo.lock1
-rw-r--r--components/layout/Cargo.toml1
-rw-r--r--components/layout/display_list_builder.rs33
-rw-r--r--components/layout/lib.rs1
-rw-r--r--components/layout/table_cell.rs2
-rw-r--r--components/layout/table_row.rs5
-rw-r--r--components/script/dom/element.rs12
-rw-r--r--components/style/gecko/conversions.rs15
-rw-r--r--components/style/gecko_bindings/sugar/ns_css_shadow_item.rs17
-rw-r--r--components/style/gecko_bindings/sugar/style_complex_color.rs51
-rw-r--r--components/style/properties/data.py3
-rw-r--r--components/style/properties/gecko.mako.rs93
-rw-r--r--components/style/properties/helpers/animated_properties.mako.rs178
-rw-r--r--components/style/properties/longhand/background.mako.rs5
-rw-r--r--components/style/properties/longhand/border.mako.rs14
-rw-r--r--components/style/properties/longhand/color.mako.rs11
-rw-r--r--components/style/properties/longhand/column.mako.rs9
-rw-r--r--components/style/properties/longhand/inherited_text.mako.rs25
-rw-r--r--components/style/properties/longhand/outline.mako.rs6
-rw-r--r--components/style/properties/longhand/svg.mako.rs12
-rw-r--r--components/style/properties/longhand/text.mako.rs7
-rw-r--r--components/style/properties/properties.mako.rs12
-rw-r--r--components/style/properties/shorthand/background.mako.rs6
-rw-r--r--components/style/properties/shorthand/border.mako.rs10
-rw-r--r--components/style/properties/shorthand/outline.mako.rs2
-rw-r--r--components/style/properties/shorthand/serialize.mako.rs6
-rw-r--r--components/style/properties/shorthand/text.mako.rs2
-rw-r--r--components/style/rule_tree/mod.rs3
-rw-r--r--components/style/values/computed/color.rs144
-rw-r--r--components/style/values/computed/image.rs8
-rw-r--r--components/style/values/computed/mod.rs93
-rw-r--r--components/style/values/specified/color.rs386
-rw-r--r--components/style/values/specified/image.rs22
-rw-r--r--components/style/values/specified/mod.rs189
-rw-r--r--components/style/values/specified/mod.rs.rej44
-rw-r--r--ports/geckolib/glue.rs8
-rw-r--r--tests/unit/style/parsing/ui.rs10
-rw-r--r--tests/unit/style/properties/serialization.rs51
-rw-r--r--tests/unit/style/stylesheets.rs4
-rw-r--r--tests/wpt/metadata-css/cssom-1_dev/html/cssstyledeclaration-csstext.htm.ini5
40 files changed, 817 insertions, 689 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 38414c4669a..217bc8c7dec 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1419,7 +1419,6 @@ dependencies = [
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"canvas_traits 0.0.1",
- "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx 0.0.1",
diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml
index 763ac1288a4..e9679887da6 100644
--- a/components/layout/Cargo.toml
+++ b/components/layout/Cargo.toml
@@ -14,7 +14,6 @@ app_units = "0.4.1"
atomic_refcell = "0.1"
bitflags = "0.7"
canvas_traits = {path = "../canvas_traits"}
-cssparser = "0.13.7"
euclid = "0.13"
fnv = "1.0"
gfx = {path = "../gfx"}
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index 6794d144a47..4a7f2814cbf 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -422,8 +422,7 @@ pub trait FragmentDisplayListBuilding {
bounds: &Rect<Au>,
stops: &[GradientItem],
direction: &LineDirection,
- repeating: bool,
- style: &ServoComputedValues)
+ repeating: bool)
-> display_list::Gradient;
fn convert_radial_gradient(&self,
@@ -431,8 +430,7 @@ pub trait FragmentDisplayListBuilding {
stops: &[GradientItem],
shape: &EndingShape,
center: &Position,
- repeating: bool,
- style: &ServoComputedValues)
+ repeating: bool)
-> display_list::RadialGradient;
/// Adds the display items necessary to paint the background linear gradient of this fragment
@@ -634,8 +632,7 @@ fn build_border_radius_for_inner_rect(outer_rect: &Rect<Au>,
}
fn convert_gradient_stops(gradient_items: &[GradientItem],
- total_length: Au,
- style: &ServoComputedValues) -> Vec<GradientStop> {
+ total_length: Au) -> Vec<GradientStop> {
// Determine the position of each stop per CSS-IMAGES § 3.4.
// Only keep the color stops, discard the color interpolation hints.
@@ -722,7 +719,7 @@ fn convert_gradient_stops(gradient_items: &[GradientItem],
};
stops.push(GradientStop {
offset: offset,
- color: style.resolve_color(stop.color).to_gfx_color()
+ color: stop.color.to_gfx_color()
})
}
stops
@@ -1192,8 +1189,7 @@ impl FragmentDisplayListBuilding for Fragment {
bounds: &Rect<Au>,
stops: &[GradientItem],
direction: &LineDirection,
- repeating: bool,
- style: &ServoComputedValues)
+ repeating: bool)
-> display_list::Gradient {
let angle = match *direction {
LineDirection::Angle(angle) => angle.radians(),
@@ -1234,7 +1230,7 @@ impl FragmentDisplayListBuilding for Fragment {
let length = Au::from_f32_px(
(delta.x.to_f32_px() * 2.0).hypot(delta.y.to_f32_px() * 2.0));
- let mut stops = convert_gradient_stops(stops, length, style);
+ let mut stops = convert_gradient_stops(stops, length);
// Only clamped gradients need to be fixed because in repeating gradients
// there is no "first" or "last" stop because they repeat infinitly in
@@ -1258,8 +1254,7 @@ impl FragmentDisplayListBuilding for Fragment {
stops: &[GradientItem],
shape: &EndingShape,
center: &Position,
- repeating: bool,
- style: &ServoComputedValues)
+ repeating: bool)
-> display_list::RadialGradient {
let center = Point2D::new(center.horizontal.to_used_value(bounds.size.width),
center.vertical.to_used_value(bounds.size.height));
@@ -1278,7 +1273,7 @@ impl FragmentDisplayListBuilding for Fragment {
},
};
- let mut stops = convert_gradient_stops(stops, radius.width, style);
+ let mut stops = convert_gradient_stops(stops, radius.width);
// Repeating gradients have no last stops that can be ignored. So
// fixup is not necessary but may actually break the gradient.
if !repeating {
@@ -1322,8 +1317,7 @@ impl FragmentDisplayListBuilding for Fragment {
let gradient = self.convert_linear_gradient(&bounds,
&gradient.items[..],
angle_or_corner,
- gradient.repeating,
- style);
+ gradient.repeating);
DisplayItem::Gradient(box GradientDisplayItem {
base: base,
gradient: gradient,
@@ -1334,8 +1328,7 @@ impl FragmentDisplayListBuilding for Fragment {
&gradient.items[..],
shape,
center,
- gradient.repeating,
- style);
+ gradient.repeating);
DisplayItem::RadialGradient(box RadialGradientDisplayItem {
base: base,
gradient: gradient,
@@ -1459,8 +1452,7 @@ impl FragmentDisplayListBuilding for Fragment {
let grad = self.convert_linear_gradient(&bounds,
&gradient.items[..],
&angle_or_corner,
- gradient.repeating,
- style);
+ gradient.repeating);
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
base: base,
@@ -1478,8 +1470,7 @@ impl FragmentDisplayListBuilding for Fragment {
&gradient.items[..],
shape,
center,
- gradient.repeating,
- style);
+ gradient.repeating);
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
base: base,
border_widths: border.to_physical(style.writing_mode),
diff --git a/components/layout/lib.rs b/components/layout/lib.rs
index 65923c10554..ca85d83e9d1 100644
--- a/components/layout/lib.rs
+++ b/components/layout/lib.rs
@@ -16,7 +16,6 @@ extern crate atomic_refcell;
extern crate bitflags;
extern crate canvas_traits;
extern crate core;
-extern crate cssparser;
extern crate euclid;
extern crate fnv;
extern crate gfx;
diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs
index 8c54297d4b5..47f74891488 100644
--- a/components/layout/table_cell.rs
+++ b/components/layout/table_cell.rs
@@ -9,7 +9,6 @@
use app_units::Au;
use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
use context::LayoutContext;
-use cssparser::Color;
use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
use euclid::{Point2D, Rect, SideOffsets2D, Size2D};
use flow::{self, Flow, FlowClass, IS_ABSOLUTELY_POSITIONED, OpaqueFlow};
@@ -22,6 +21,7 @@ use std::fmt;
use style::computed_values::{border_collapse, border_top_style, vertical_align};
use style::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
use style::properties::ServoComputedValues;
+use style::values::computed::Color;
use table::InternalTable;
use table_row::{CollapsedBorder, CollapsedBorderProvenance};
diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs
index 8d074f59c52..2fb61a336de 100644
--- a/components/layout/table_row.rs
+++ b/components/layout/table_row.rs
@@ -9,7 +9,6 @@
use app_units::Au;
use block::{BlockFlow, ISizeAndMarginsComputer};
use context::LayoutContext;
-use cssparser::{Color, RGBA};
use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
use euclid::Point2D;
use flow::{self, EarlyAbsolutePositionInfo, Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
@@ -26,7 +25,7 @@ use style::computed_values::{border_collapse, border_spacing, border_top_style};
use style::logical_geometry::{LogicalSize, PhysicalSide, WritingMode};
use style::properties::ServoComputedValues;
use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
-use style::values::computed::LengthOrPercentageOrAuto;
+use style::values::computed::{Color, LengthOrPercentageOrAuto};
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable, VecExt};
use table_cell::{CollapsedBordersForCell, TableCellFlow};
@@ -606,7 +605,7 @@ impl CollapsedBorder {
CollapsedBorder {
style: border_top_style::T::none,
width: Au(0),
- color: Color::RGBA(RGBA::transparent()),
+ color: Color::transparent(),
provenance: CollapsedBorderProvenance::FromTable,
}
}
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index cb882f53463..189410ce77a 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -4,7 +4,6 @@
//! Element nodes.
-use cssparser::Color;
use devtools_traits::AttrInfo;
use dom::activation::Activatable;
use dom::attr::{Attr, AttrHelpersForLayout};
@@ -113,7 +112,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;
use stylesheet_loader::StylesheetOwner;
// TODO: Update focus state when the top-level browsing context gains or loses system focus,
@@ -422,8 +421,8 @@ impl LayoutElementHelpers for LayoutJS<Element> {
if let Some(color) = bgcolor {
hints.push(from_declaration(
shared_lock,
- PropertyDeclaration::BackgroundColor(
- CSSColor { parsed: Color::RGBA(color), authored: None })));
+ PropertyDeclaration::BackgroundColor(color.into())
+ ));
}
let background = if let Some(this) = self.downcast::<HTMLBodyElement>() {
@@ -457,10 +456,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Color(
- longhands::color::SpecifiedValue(CSSColor {
- parsed: Color::RGBA(color),
- authored: None,
- })
+ longhands::color::SpecifiedValue(color.into())
)
));
}
diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs
index 9f222690404..4266c61826a 100644
--- a/components/style/gecko/conversions.rs
+++ b/components/style/gecko/conversions.rs
@@ -183,7 +183,6 @@ impl nsStyleImage {
}
fn set_gradient(&mut self, gradient: Gradient) {
- use cssparser::Color as CSSColor;
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_CIRCULAR, NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL};
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_LINEAR, NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER};
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE};
@@ -321,19 +320,7 @@ impl nsStyleImage {
match *item {
GradientItem::ColorStop(ref stop) => {
- gecko_stop.mColor = match stop.color {
- CSSColor::CurrentColor => {
- // TODO(emilio): gecko just stores an nscolor,
- // and it doesn't seem to support currentColor
- // as value in a gradient.
- //
- // Double-check it and either remove
- // currentColor for servo or see how gecko
- // handles this.
- 0
- },
- CSSColor::RGBA(ref rgba) => convert_rgba_to_nscolor(rgba),
- };
+ gecko_stop.mColor = convert_rgba_to_nscolor(&stop.color);
gecko_stop.mIsInterpolationHint = false;
coord.set(stop.position);
},
diff --git a/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs b/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs
index 003da073b23..fe818d71330 100644
--- a/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs
+++ b/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs
@@ -5,10 +5,9 @@
//! Rust helpers for Gecko's `nsCSSShadowItem`.
use app_units::Au;
-use cssparser::Color;
use gecko::values::{convert_rgba_to_nscolor, convert_nscolor_to_rgba};
use gecko_bindings::structs::nsCSSShadowItem;
-use values::computed::Shadow;
+use values::computed::{Color, Shadow};
impl nsCSSShadowItem {
/// Set this item to the given shadow value.
@@ -18,14 +17,14 @@ impl nsCSSShadowItem {
self.mRadius = other.blur_radius.0;
self.mSpread = other.spread_radius.0;
self.mInset = other.inset;
- self.mColor = match other.color {
- Color::RGBA(rgba) => {
- self.mHasColor = true;
- convert_rgba_to_nscolor(&rgba)
- },
+ if other.color.is_currentcolor() {
// TODO handle currentColor
// https://bugzilla.mozilla.org/show_bug.cgi?id=760345
- Color::CurrentColor => 0,
+ self.mHasColor = false;
+ self.mColor = 0;
+ } else {
+ self.mHasColor = true;
+ self.mColor = convert_rgba_to_nscolor(&other.color.color);
}
}
@@ -37,7 +36,7 @@ impl nsCSSShadowItem {
blur_radius: Au(self.mRadius),
spread_radius: Au(self.mSpread),
inset: self.mInset,
- color: Color::RGBA(convert_nscolor_to_rgba(self.mColor)),
+ color: Color::rgba(convert_nscolor_to_rgba(self.mColor)),
}
}
}
diff --git a/components/style/gecko_bindings/sugar/style_complex_color.rs b/components/style/gecko_bindings/sugar/style_complex_color.rs
index 47d9046e874..cd0e408b26f 100644
--- a/components/style/gecko_bindings/sugar/style_complex_color.rs
+++ b/components/style/gecko_bindings/sugar/style_complex_color.rs
@@ -4,10 +4,10 @@
//! Rust helpers to interact with Gecko's StyleComplexColor.
-use cssparser;
use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
use gecko_bindings::structs::{nscolor, StyleComplexColor};
-use values;
+use values::{Auto, Either};
+use values::computed::Color as ComputedColor;
impl From<nscolor> for StyleComplexColor {
fn from(other: nscolor) -> Self {
@@ -39,40 +39,41 @@ impl StyleComplexColor {
}
}
-impl From<cssparser::Color> for StyleComplexColor {
- fn from(other: cssparser::Color) -> Self {
- use cssparser::Color;
-
- match other {
- Color::RGBA(rgba) => convert_rgba_to_nscolor(&rgba).into(),
- Color::CurrentColor => StyleComplexColor::current_color(),
+impl From<ComputedColor> for StyleComplexColor {
+ fn from(other: ComputedColor) -> Self {
+ StyleComplexColor {
+ mColor: convert_rgba_to_nscolor(&other.color).into(),
+ mForegroundRatio: other.foreground_ratio,
+ mIsAuto: false,
}
}
}
-impl From<StyleComplexColor> for values::computed::ColorOrAuto {
- fn from(color: StyleComplexColor) -> Self {
- use values::{Auto, Either};
-
- if color.mIsAuto {
- return Either::Second(Auto);
+impl From<StyleComplexColor> for ComputedColor {
+ fn from(other: StyleComplexColor) -> Self {
+ debug_assert!(!other.mIsAuto);
+ ComputedColor {
+ color: convert_nscolor_to_rgba(other.mColor),
+ foreground_ratio: other.mForegroundRatio,
}
+ }
+}
- Either::First(color.into())
+impl From<Either<ComputedColor, Auto>> for StyleComplexColor {
+ fn from(other: Either<ComputedColor, Auto>) -> Self {
+ match other {
+ Either::First(color) => color.into(),
+ Either::Second(_auto) => StyleComplexColor::auto(),
+ }
}
}
-impl From<StyleComplexColor> for cssparser::Color {
+impl From<StyleComplexColor> for Either<ComputedColor, Auto> {
fn from(other: StyleComplexColor) -> Self {
- use cssparser::Color;
-
- if other.mForegroundRatio == 0 {
- Color::RGBA(convert_nscolor_to_rgba(other.mColor))
- } else if other.mForegroundRatio == 255 {
- Color::CurrentColor
+ if !other.mIsAuto {
+ Either::First(other.into())
} else {
- // FIXME #13546 handle interpolation values
- Color::CurrentColor
+ Either::Second(Auto)
}
}
}
diff --git a/components/style/properties/data.py b/components/style/properties/data.py
index 06735ef888b..15d9f2fc89a 100644
--- a/components/style/properties/data.py
+++ b/components/style/properties/data.py
@@ -148,7 +148,7 @@ class Longhand(object):
def __init__(self, style_struct, name, spec=None, animation_value_type=None, derived_from=None, keyword=None,
predefined_type=None, custom_cascade=False, experimental=False, internal=False,
need_clone=False, need_index=False, gecko_ffi_name=None, depend_on_viewport_size=False,
- allowed_in_keyframe_block=True, complex_color=False, cast_type='u8',
+ allowed_in_keyframe_block=True, cast_type='u8',
has_uncacheable_values=False, logical=False, alias=None, extra_prefixes=None, boxed=False,
flags=None, allowed_in_page_rule=False, allow_quirks=False, ignored_when_colors_disabled=False,
vector=False):
@@ -169,7 +169,6 @@ class Longhand(object):
self.gecko_ffi_name = gecko_ffi_name or "m" + self.camel_case
self.depend_on_viewport_size = depend_on_viewport_size
self.derived_from = (derived_from or "").split()
- self.complex_color = complex_color
self.cast_type = cast_type
self.logical = arg_to_bool(logical)
self.alias = alias.split() if alias else []
diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs
index 3c0b57c9fe0..0df0ee4bde6 100644
--- a/components/style/properties/gecko.mako.rs
+++ b/components/style/properties/gecko.mako.rs
@@ -11,7 +11,6 @@
<%namespace name="helpers" file="/helpers.mako.rs" />
use app_units::Au;
-use cssparser::Color;
use custom_properties::ComputedValuesMap;
use gecko_bindings::bindings;
% for style_struct in data.style_structs:
@@ -43,7 +42,7 @@ use gecko_bindings::bindings::Gecko_SetNullImageValue;
use gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
use gecko_bindings::bindings::{Gecko_ResetFilters, Gecko_CopyFiltersFrom};
use gecko_bindings::bindings::RawGeckoPresContextBorrowed;
-use gecko_bindings::structs::{self, StyleComplexColor};
+use gecko_bindings::structs;
use gecko_bindings::structs::nsCSSPropertyID;
use gecko_bindings::structs::nsStyleVariables;
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
@@ -316,32 +315,15 @@ def set_gecko_property(ffi_name, expr):
}
</%def>
-/// Convert a Servo color into an nscolor; with currentColor as 0
-///
-/// Call sites will need to be updated after https://bugzilla.mozilla.org/show_bug.cgi?id=760345
-fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
- match color {
- Color::RGBA(rgba) => {
- convert_rgba_to_nscolor(&rgba)
- },
- Color::CurrentColor => 0,
- }
-}
-
-<%def name="impl_color_setter(ident, gecko_ffi_name, complex_color=True)">
+<%def name="impl_color_setter(ident, gecko_ffi_name)">
#[allow(unreachable_code)]
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
- % if complex_color:
- let result = v.into();
- % else:
- let result = color_to_nscolor_zero_currentcolor(v);
- % endif
- ${set_gecko_property(gecko_ffi_name, "result")}
+ ${set_gecko_property(gecko_ffi_name, "v.into()")}
}
</%def>
-<%def name="impl_color_copy(ident, gecko_ffi_name, complex_color=True)">
+<%def name="impl_color_copy(ident, gecko_ffi_name)">
#[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) {
let color = ${get_gecko_property(gecko_ffi_name, self_param = "other")};
@@ -349,14 +331,10 @@ fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
}
</%def>
-<%def name="impl_color_clone(ident, gecko_ffi_name, complex_color=True)">
+<%def name="impl_color_clone(ident, gecko_ffi_name)">
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
- % if complex_color:
- ${get_gecko_property(gecko_ffi_name)}.into()
- % else:
- Color::RGBA(convert_nscolor_to_rgba(${get_gecko_property(gecko_ffi_name)}))
- % endif
+ ${get_gecko_property(gecko_ffi_name)}.into()
}
</%def>
@@ -408,15 +386,29 @@ fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
% endif
</%def>
-<%def name="impl_color(ident, gecko_ffi_name, need_clone=False, complex_color=True)">
-<%call expr="impl_color_setter(ident, gecko_ffi_name, complex_color)"></%call>
-<%call expr="impl_color_copy(ident, gecko_ffi_name, complex_color)"></%call>
+<%def name="impl_color(ident, gecko_ffi_name, need_clone=False)">
+<%call expr="impl_color_setter(ident, gecko_ffi_name)"></%call>
+<%call expr="impl_color_copy(ident, gecko_ffi_name)"></%call>
% if need_clone:
- <%call expr="impl_color_clone(ident, gecko_ffi_name, complex_color)"></%call>
+ <%call expr="impl_color_clone(ident, gecko_ffi_name)"></%call>
% endif
</%def>
-<%def name="impl_svg_paint(ident, gecko_ffi_name, need_clone=False, complex_color=True)">
+<%def name="impl_rgba_color(ident, gecko_ffi_name, need_clone=False)">
+ #[allow(non_snake_case)]
+ pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
+ ${set_gecko_property(gecko_ffi_name, "convert_rgba_to_nscolor(&v)")}
+ }
+ <%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
+ % if need_clone:
+ #[allow(non_snake_case)]
+ pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
+ convert_nscolor_to_rgba(${get_gecko_property(gecko_ffi_name)})
+ }
+ % endif
+</%def>
+
+<%def name="impl_svg_paint(ident, gecko_ffi_name, need_clone=False)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, mut v: longhands::${ident}::computed_value::T) {
use values::generics::SVGPaintKind;
@@ -444,14 +436,14 @@ fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
SVGPaintKind::Color(color) => {
paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_Color;
unsafe {
- *paint.mPaint.mColor.as_mut() = color_to_nscolor_zero_currentcolor(color);
+ *paint.mPaint.mColor.as_mut() = convert_rgba_to_nscolor(&color);
}
}
}
if let Some(fallback) = fallback {
paint.mFallbackType = nsStyleSVGFallbackType::eStyleSVGFallbackType_Color;
- paint.mFallbackColor = color_to_nscolor_zero_currentcolor(fallback);
+ paint.mFallbackColor = convert_rgba_to_nscolor(&fallback);
}
}
@@ -472,7 +464,7 @@ fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
use self::structs::nsStyleSVGFallbackType;
let ref paint = ${get_gecko_property(gecko_ffi_name)};
let fallback = if let nsStyleSVGFallbackType::eStyleSVGFallbackType_Color = paint.mFallbackType {
- Some(Color::RGBA(convert_nscolor_to_rgba(paint.mFallbackColor)))
+ Some(convert_nscolor_to_rgba(paint.mFallbackColor))
} else {
None
};
@@ -485,7 +477,7 @@ fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
SVGPaintKind::None
}
nsStyleSVGPaintType::eStyleSVGPaintType_Color => {
- unsafe { SVGPaintKind::Color(Color::RGBA(convert_nscolor_to_rgba(*paint.mPaint.mColor.as_ref()))) }
+ unsafe { SVGPaintKind::Color(convert_nscolor_to_rgba(*paint.mPaint.mColor.as_ref())) }
}
};
SVGPaint {
@@ -716,7 +708,8 @@ impl Debug for ${style_struct.gecko_struct_name} {
"Number": impl_simple,
"Integer": impl_simple,
"Opacity": impl_simple,
- "CSSColor": impl_color,
+ "Color": impl_color,
+ "RGBAColor": impl_rgba_color,
"SVGPaint": impl_svg_paint,
"UrlOrNone": impl_css_url,
}
@@ -736,8 +729,6 @@ impl Debug for ${style_struct.gecko_struct_name} {
args.update(cast_type=longhand.cast_type)
else:
method = predefined_types[longhand.predefined_type]
- if longhand.predefined_type in ["CSSColor"]:
- args.update(complex_color=longhand.complex_color)
method(**args)
@@ -948,7 +939,7 @@ fn static_assert() {
structs::Side::eSide${to_camel_case(side.ident)});
}
for color in colors {
- let c = color_to_nscolor_zero_currentcolor(*color);
+ let c = convert_rgba_to_nscolor(color);
unsafe {
bindings::Gecko_AppendMozBorderColors(&mut self.gecko,
structs::Side::eSide${to_camel_case(side.ident)},
@@ -4268,25 +4259,7 @@ clip-path
}
}
- pub fn set_caret_color(&mut self, v: longhands::caret_color::computed_value::T){
- use values::Either;
-
- match v {
- Either::First(color) => {
- self.gecko.mCaretColor = StyleComplexColor::from(color);
- }
- Either::Second(_auto) => {
- self.gecko.mCaretColor = StyleComplexColor::auto();
- }
- }
- }
-
- pub fn copy_caret_color_from(&mut self, other: &Self){
- self.gecko.mCaretColor = other.gecko.mCaretColor;
- }
-
- <%call expr="impl_color_clone('caret_color', 'mCaretColor')"></%call>
-
+ <%call expr="impl_color('caret_color', 'mCaretColor', need_clone=True)"></%call>
</%self:impl_trait>
<%self:impl_trait style_struct_name="Column"
diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs
index 4ba7e6b505a..41501e5ddd8 100644
--- a/components/style/properties/helpers/animated_properties.mako.rs
+++ b/components/style/properties/helpers/animated_properties.mako.rs
@@ -7,7 +7,7 @@
<% from data import SYSTEM_FONT_LONGHANDS %>
use app_units::Au;
-use cssparser::{Color as CSSParserColor, Parser, RGBA, serialize_identifier};
+use cssparser::{Parser, RGBA, serialize_identifier};
use euclid::{Point2D, Size2D};
#[cfg(feature = "gecko")] use gecko_bindings::bindings::RawServoAnimationValueMap;
#[cfg(feature = "gecko")] use gecko_bindings::structs::RawGeckoGfxMatrix4x4;
@@ -38,7 +38,7 @@ use values::CSSFloat;
use values::{Auto, Either};
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
use values::computed::{BorderCornerRadius, ClipRect};
-use values::computed::{CalcLengthOrPercentage, Context, ComputedValueAsSpecified};
+use values::computed::{CalcLengthOrPercentage, Color, Context, ComputedValueAsSpecified};
use values::computed::{LengthOrPercentage, MaxLength, MozLength, Shadow, ToComputedValue};
use values::generics::{SVGPaint, SVGPaintKind};
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
@@ -2721,38 +2721,19 @@ impl Animatable for IntermediateRGBA {
}
}
-impl From<Either<CSSParserColor, Auto>> for Either<IntermediateColor, Auto> {
- fn from(from: Either<CSSParserColor, Auto>) -> Either<IntermediateColor, Auto> {
+impl From<Either<Color, Auto>> for Either<IntermediateColor, Auto> {
+ fn from(from: Either<Color, Auto>) -> Either<IntermediateColor, Auto> {
match from {
- Either::First(from) =>
- match from {
- CSSParserColor::RGBA(color) =>
- Either::First(IntermediateColor::IntermediateRGBA(
- IntermediateRGBA::new(color.red_f32(),
- color.green_f32(),
- color.blue_f32(),
- color.alpha_f32()))),
- CSSParserColor::CurrentColor =>
- Either::First(IntermediateColor::CurrentColor),
- },
+ Either::First(from) => Either::First(from.into()),
Either::Second(Auto) => Either::Second(Auto),
}
}
}
-impl From<Either<IntermediateColor, Auto>> for Either<CSSParserColor, Auto> {
- fn from(from: Either<IntermediateColor, Auto>) -> Either<CSSParserColor, Auto> {
+impl From<Either<IntermediateColor, Auto>> for Either<Color, Auto> {
+ fn from(from: Either<IntermediateColor, Auto>) -> Either<Color, Auto> {
match from {
- Either::First(from) =>
- match from {
- IntermediateColor::IntermediateRGBA(color) =>
- Either::First(CSSParserColor::RGBA(RGBA::from_floats(color.red,
- color.green,
- color.blue,
- color.alpha))),
- IntermediateColor::CurrentColor =>
- Either::First(CSSParserColor::CurrentColor),
- },
+ Either::First(from) => Either::First(from.into()),
Either::Second(Auto) => Either::Second(Auto),
}
}
@@ -2761,22 +2742,89 @@ impl From<Either<IntermediateColor, Auto>> for Either<CSSParserColor, Auto> {
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
-pub enum IntermediateColor {
- CurrentColor,
- IntermediateRGBA(IntermediateRGBA),
+pub struct IntermediateColor {
+ color: IntermediateRGBA,
+ foreground_ratio: f32,
+}
+
+impl IntermediateColor {
+ fn currentcolor() -> Self {
+ IntermediateColor {
+ color: IntermediateRGBA::transparent(),
+ foreground_ratio: 1.,
+ }
+ }
+
+ fn transparent() -> Self {
+ IntermediateColor {
+ color: IntermediateRGBA::transparent(),
+ foreground_ratio: 0.,
+ }
+ }
+
+ fn is_currentcolor(&self) -> bool {
+ self.foreground_ratio >= 1.
+ }
+
+ fn is_numeric(&self) -> bool {
+ self.foreground_ratio <= 0.
+ }
+
+ fn effective_intermediate_rgba(&self) -> IntermediateRGBA {
+ IntermediateRGBA {
+ alpha: self.color.alpha * (1. - self.foreground_ratio),
+ .. self.color
+ }
+ }
}
impl Animatable for IntermediateColor {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
- match (*self, *other) {
- (IntermediateColor::IntermediateRGBA(ref this),
- IntermediateColor::IntermediateRGBA(ref other)) => {
- this.add_weighted(other, self_portion, other_portion)
- .map(IntermediateColor::IntermediateRGBA)
+ // Common cases are interpolating between two numeric colors,
+ // two currentcolors, and a numeric color and a currentcolor.
+ //
+ // Note: this algorithm assumes self_portion + other_portion
+ // equals to one, so it may be broken for additive operation.
+ // To properly support additive color interpolation, we would
+ // need two ratio fields in computed color types.
+ if self.foreground_ratio == other.foreground_ratio {
+ if self.is_currentcolor() {
+ Ok(IntermediateColor::currentcolor())
+ } else {
+ Ok(IntermediateColor {
+ color: self.color.add_weighted(&other.color, self_portion, other_portion)?,
+ foreground_ratio: self.foreground_ratio,
+ })
}
- // FIXME: Bug 1345709: Implement currentColor animations.
- _ => Err(()),
+ } else if self.is_currentcolor() && other.is_numeric() {
+ Ok(IntermediateColor {
+ color: other.color,
+ foreground_ratio: self_portion as f32,
+ })
+ } else if self.is_numeric() && other.is_currentcolor() {
+ Ok(IntermediateColor {
+ color: self.color,
+ foreground_ratio: other_portion as f32,
+ })
+ } else {
+ // For interpolating between two complex colors, we need to
+ // generate colors with effective alpha value.
+ let self_color = self.effective_intermediate_rgba();
+ let other_color = other.effective_intermediate_rgba();
+ let color = self_color.add_weighted(&other_color, self_portion, other_portion)?;
+ // Then we compute the final foreground ratio, and derive
+ // the final alpha value from the effective alpha value.
+ let foreground_ratio = self.foreground_ratio
+ .add_weighted(&other.foreground_ratio, self_portion, other_portion)?;
+ let alpha = color.alpha / (1. - foreground_ratio);
+ Ok(IntermediateColor {
+ color: IntermediateRGBA {
+ alpha: alpha,
+ .. color
+ },
+ foreground_ratio: foreground_ratio,
+ })
}
}
@@ -2787,45 +2835,49 @@ impl Animatable for IntermediateColor {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
- match (*self, *other) {
- (IntermediateColor::IntermediateRGBA(ref this), IntermediateColor::IntermediateRGBA(ref other)) => {
- this.compute_squared_distance(other)
- },
- _ => Ok(0.0),
+ // All comments in add_weighted also applies here.
+ if self.foreground_ratio == other.foreground_ratio {
+ if self.is_currentcolor() {
+ Ok(0.)
+ } else {
+ self.color.compute_squared_distance(&other.color)
+ }
+ } else if self.is_currentcolor() && other.is_numeric() {
+ Ok(IntermediateRGBA::transparent().compute_squared_distance(&other.color)? + 1.)
+ } else if self.is_numeric() && other.is_currentcolor() {
+ Ok(self.color.compute_squared_distance(&IntermediateRGBA::transparent())? + 1.)
+ } else {
+ let self_color = self.effective_intermediate_rgba();
+ let other_color = other.effective_intermediate_rgba();
+ let dist = self_color.compute_squared_distance(&other_color)?;
+ let ratio_diff = (self.foreground_ratio - other.foreground_ratio) as f64;
+ Ok(dist + ratio_diff * ratio_diff)
}
}
}
-impl From<CSSParserColor> for IntermediateColor {
- fn from(color: CSSParserColor) -> IntermediateColor {
- match color {
- CSSParserColor::RGBA(color) =>
- IntermediateColor::IntermediateRGBA(IntermediateRGBA::new(color.red_f32(),
- color.green_f32(),
- color.blue_f32(),
- color.alpha_f32())),
- CSSParserColor::CurrentColor => IntermediateColor::CurrentColor,
+impl From<Color> for IntermediateColor {
+ fn from(color: Color) -> IntermediateColor {
+ IntermediateColor {
+ color: color.color.into(),
+ foreground_ratio: color.foreground_ratio as f32 * (1. / 255.),
}
}
}
-impl From<IntermediateColor> for CSSParserColor {
- fn from(color: IntermediateColor) -> CSSParserColor {
- match color {
- IntermediateColor::IntermediateRGBA(color) =>
- CSSParserColor::RGBA(RGBA::from_floats(color.red,
- color.green,
- color.blue,
- color.alpha)),
- IntermediateColor::CurrentColor => CSSParserColor::CurrentColor,
+impl From<IntermediateColor> for Color {
+ fn from(color: IntermediateColor) -> Color {
+ Color {
+ color: color.color.into(),
+ foreground_ratio: (color.foreground_ratio * 255.).round() as u8,
}
}
}
/// Animatable SVGPaint
-pub type IntermediateSVGPaint = SVGPaint<IntermediateColor>;
+pub type IntermediateSVGPaint = SVGPaint<IntermediateRGBA>;
/// Animatable SVGPaintKind
-pub type IntermediateSVGPaintKind = SVGPaintKind<IntermediateColor>;
+pub type IntermediateSVGPaintKind = SVGPaintKind<IntermediateRGBA>;
impl From<::values::computed::SVGPaint> for IntermediateSVGPaint {
fn from(paint: ::values::computed::SVGPaint) -> IntermediateSVGPaint {
@@ -3024,7 +3076,7 @@ impl Animatable for IntermediateShadowList {
offset_y: Au(0),
blur_radius: Au(0),
spread_radius: Au(0),
- color: IntermediateColor::IntermediateRGBA(IntermediateRGBA::transparent()),
+ color: IntermediateColor::transparent(),
inset: false,
};
diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs
index 4937a2569b0..9b799c220b9 100644
--- a/components/style/properties/longhand/background.mako.rs
+++ b/components/style/properties/longhand/background.mako.rs
@@ -6,12 +6,11 @@
<% data.new_style_struct("Background", inherited=False) %>
-${helpers.predefined_type("background-color", "CSSColor",
- "::cssparser::Color::RGBA(::cssparser::RGBA::transparent())",
+${helpers.predefined_type("background-color", "Color",
+ "computed_value::T::transparent()",
initial_specified_value="SpecifiedValue::transparent()",
spec="https://drafts.csswg.org/css-backgrounds/#background-color",
animation_value_type="IntermediateColor",
- complex_color=True,
ignored_when_colors_disabled=True,
allow_quirks=True)}
diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs
index 693d1f32551..0fd7196baf5 100644
--- a/components/style/properties/longhand/border.mako.rs
+++ b/components/style/properties/longhand/border.mako.rs
@@ -16,8 +16,8 @@
return "https://drafts.csswg.org/css-backgrounds/#border-%s-%s" % (side[0], kind)
%>
% for side in ALL_SIDES:
- ${helpers.predefined_type("border-%s-color" % side[0], "CSSColor",
- "::cssparser::Color::CurrentColor",
+ ${helpers.predefined_type("border-%s-color" % side[0], "Color",
+ "computed_value::T::currentcolor()",
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-color"),
spec=maybe_logical_spec(side, "color"),
animation_value_type="IntermediateColor",
@@ -66,21 +66,21 @@ ${helpers.gecko_keyword_conversion(Keyword('border-style',
ignored_when_colors_disabled="True">
use std::fmt;
use style_traits::ToCss;
- use values::specified::CSSColor;
+ use values::specified::RGBAColor;
no_viewport_percentage!(SpecifiedValue);
pub mod computed_value {
- use values::computed::CSSColor;
+ use cssparser::RGBA;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct T(pub Option<Vec<CSSColor>>);
+ pub struct T(pub Option<Vec<RGBA>>);
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum SpecifiedValue {
None,
- Colors(Vec<CSSColor>),
+ Colors(Vec<RGBAColor>),
}
impl ToCss for computed_value::T {
@@ -168,7 +168,7 @@ ${helpers.gecko_keyword_conversion(Keyword('border-style',
}
let mut result = Vec::new();
- while let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
+ while let Ok(value) = input.try(|i| RGBAColor::parse(context, i)) {
result.push(value);
}
diff --git a/components/style/properties/longhand/color.mako.rs b/components/style/properties/longhand/color.mako.rs
index 0728516ab41..fe5e411801e 100644
--- a/components/style/properties/longhand/color.mako.rs
+++ b/components/style/properties/longhand/color.mako.rs
@@ -13,25 +13,26 @@
ignored_when_colors_disabled="True"
spec="https://drafts.csswg.org/css-color/#color">
use cssparser::RGBA;
- use values::specified::{AllowQuirks, Color, CSSColor};
+ use values::specified::{AllowQuirks, Color};
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T {
- self.0.parsed.to_computed_value(context)
+ self.0.to_computed_value(context)
+ .to_rgba(context.inherited_style.get_color().clone_color())
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
- SpecifiedValue(Color::RGBA(*computed).into())
+ SpecifiedValue(Color::rgba(*computed).into())
}
}
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToCss)]
- pub struct SpecifiedValue(pub CSSColor);
+ pub struct SpecifiedValue(pub Color);
no_viewport_percentage!(SpecifiedValue);
pub mod computed_value {
@@ -43,7 +44,7 @@
RGBA::new(0, 0, 0, 255) // black
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
- CSSColor::parse_quirky(context, input, AllowQuirks::Yes).map(SpecifiedValue)
+ Color::parse_quirky(context, input, AllowQuirks::Yes).map(SpecifiedValue)
}
// FIXME(#15973): Add servo support for system colors
diff --git a/components/style/properties/longhand/column.mako.rs b/components/style/properties/longhand/column.mako.rs
index 2c99a7f1dc3..440e5d94d81 100644
--- a/components/style/properties/longhand/column.mako.rs
+++ b/components/style/properties/longhand/column.mako.rs
@@ -51,12 +51,11 @@ ${helpers.predefined_type("column-rule-width",
extra_prefixes="moz")}
// https://drafts.csswg.org/css-multicol-1/#crc
-${helpers.predefined_type("column-rule-color", "CSSColor",
- "::cssparser::Color::CurrentColor",
- initial_specified_value="specified::CSSColor::currentcolor()",
+${helpers.predefined_type("column-rule-color", "Color",
+ "computed_value::T::currentcolor()",
+ initial_specified_value="specified::Color::currentcolor()",
products="gecko", animation_value_type="IntermediateColor", extra_prefixes="moz",
- complex_color=True, need_clone=True,
- ignored_when_colors_disabled=True,
+ need_clone=True, ignored_when_colors_disabled=True,
spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-color")}
${helpers.single_keyword("column-span", "none all",
diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs
index 9b4004712ec..649caa5cece 100644
--- a/components/style/properties/longhand/inherited_text.mako.rs
+++ b/components/style/properties/longhand/inherited_text.mako.rs
@@ -685,12 +685,11 @@ ${helpers.predefined_type("word-spacing",
% endif
</%helpers:longhand>
-${helpers.predefined_type("text-emphasis-color", "CSSColor",
- "::cssparser::Color::CurrentColor",
- initial_specified_value="specified::CSSColor::currentcolor()",
+${helpers.predefined_type("text-emphasis-color", "Color",
+ "computed_value::T::currentcolor()",
+ initial_specified_value="specified::Color::currentcolor()",
products="gecko", animation_value_type="IntermediateColor",
- complex_color=True, need_clone=True,
- ignored_when_colors_disabled=True,
+ need_clone=True, ignored_when_colors_disabled=True,
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color")}
@@ -705,20 +704,18 @@ ${helpers.predefined_type(
// CSS Compatibility
// https://compat.spec.whatwg.org
${helpers.predefined_type(
- "-webkit-text-fill-color", "CSSColor",
- "CSSParserColor::CurrentColor",
+ "-webkit-text-fill-color", "Color",
+ "computed_value::T::currentcolor()",
products="gecko", animation_value_type="IntermediateColor",
- complex_color=True, need_clone=True,
- ignored_when_colors_disabled=True,
+ need_clone=True, ignored_when_colors_disabled=True,
spec="https://compat.spec.whatwg.org/#the-webkit-text-fill-color")}
${helpers.predefined_type(
- "-webkit-text-stroke-color", "CSSColor",
- "CSSParserColor::CurrentColor",
- initial_specified_value="specified::CSSColor::currentcolor()",
+ "-webkit-text-stroke-color", "Color",
+ "computed_value::T::currentcolor()",
+ initial_specified_value="specified::Color::currentcolor()",
products="gecko", animation_value_type="IntermediateColor",
- complex_color=True, need_clone=True,
- ignored_when_colors_disabled=True,
+ need_clone=True, ignored_when_colors_disabled=True,
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color")}
${helpers.predefined_type("-webkit-text-stroke-width",
diff --git a/components/style/properties/longhand/outline.mako.rs b/components/style/properties/longhand/outline.mako.rs
index 1640953e305..03ec187135e 100644
--- a/components/style/properties/longhand/outline.mako.rs
+++ b/components/style/properties/longhand/outline.mako.rs
@@ -10,9 +10,9 @@
additional_methods=[Method("outline_has_nonzero_width", "bool")]) %>
// TODO(pcwalton): `invert`
-${helpers.predefined_type("outline-color", "CSSColor", "computed::CSSColor::CurrentColor",
- initial_specified_value="specified::CSSColor::currentcolor()",
- animation_value_type="IntermediateColor", complex_color=True, need_clone=True,
+${helpers.predefined_type("outline-color", "Color", "computed_value::T::currentcolor()",
+ initial_specified_value="specified::Color::currentcolor()",
+ animation_value_type="IntermediateColor", need_clone=True,
ignored_when_colors_disabled=True,
spec="https://drafts.csswg.org/css-ui/#propdef-outline-color")}
diff --git a/components/style/properties/longhand/svg.mako.rs b/components/style/properties/longhand/svg.mako.rs
index c9704795b8a..9021121f370 100644
--- a/components/style/properties/longhand/svg.mako.rs
+++ b/components/style/properties/longhand/svg.mako.rs
@@ -20,8 +20,8 @@ ${helpers.single_keyword("vector-effect", "none non-scaling-stroke",
// Section 13 - Gradients and Patterns
${helpers.predefined_type(
- "stop-color", "CSSColor",
- "CSSParserColor::RGBA(RGBA::new(0, 0, 0, 255))",
+ "stop-color", "RGBAColor",
+ "RGBA::new(0, 0, 0, 255)",
products="gecko",
animation_value_type="none",
spec="https://www.w3.org/TR/SVGTiny12/painting.html#StopColorProperty")}
@@ -34,8 +34,8 @@ ${helpers.predefined_type("stop-opacity", "Opacity", "1.0",
// Section 15 - Filter Effects
${helpers.predefined_type(
- "flood-color", "CSSColor",
- "CSSParserColor::RGBA(RGBA::new(0, 0, 0, 255))",
+ "flood-color", "RGBAColor",
+ "RGBA::new(0, 0, 0, 255)",
products="gecko",
animation_value_type="none",
spec="https://www.w3.org/TR/SVG/filters.html#FloodColorProperty")}
@@ -45,8 +45,8 @@ ${helpers.predefined_type("flood-opacity", "Opacity",
spec="https://www.w3.org/TR/SVG/filters.html#FloodOpacityProperty")}
${helpers.predefined_type(
- "lighting-color", "CSSColor",
- "CSSParserColor::RGBA(RGBA::new(255, 255, 255, 255))",
+ "lighting-color", "RGBAColor",
+ "RGBA::new(255, 255, 255, 255)",
products="gecko",
animation_value_type="none",
spec="https://www.w3.org/TR/SVG/filters.html#LightingColorProperty")}
diff --git a/components/style/properties/longhand/text.mako.rs b/components/style/properties/longhand/text.mako.rs
index d636ed3cb64..08113b228f2 100644
--- a/components/style/properties/longhand/text.mako.rs
+++ b/components/style/properties/longhand/text.mako.rs
@@ -278,10 +278,9 @@ ${helpers.single_keyword("text-decoration-style",
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-style")}
${helpers.predefined_type(
- "text-decoration-color", "CSSColor",
- "computed::CSSColor::CurrentColor",
- initial_specified_value="specified::CSSColor::currentcolor()",
- complex_color=True,
+ "text-decoration-color", "Color",
+ "computed_value::T::currentcolor()",
+ initial_specified_value="specified::Color::currentcolor()",
products="gecko",
animation_value_type="IntermediateColor",
ignored_when_colors_disabled=True,
diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs
index a0264d41e8c..9e8420fa471 100644
--- a/components/style/properties/properties.mako.rs
+++ b/components/style/properties/properties.mako.rs
@@ -18,7 +18,7 @@ use std::ops::Deref;
use stylearc::{Arc, UniqueArc};
use app_units::Au;
-#[cfg(feature = "servo")] use cssparser::{Color as CSSParserColor, RGBA};
+#[cfg(feature = "servo")] use cssparser::RGBA;
use cssparser::{Parser, TokenSerializationType, serialize_identifier};
use error_reporting::ParseErrorReporter;
#[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D;
@@ -40,7 +40,6 @@ use stylesheets::{CssRuleType, MallocSizeOf, MallocSizeOfFn, Origin, UrlExtraDat
#[cfg(feature = "servo")] use values::Either;
use values::generics::text::LineHeight;
use values::computed;
-use values::specified::Color;
use cascade_info::CascadeInfo;
use rule_tree::{CascadeLevel, StrongRuleNode};
use style_adjuster::StyleAdjuster;
@@ -1938,11 +1937,8 @@ impl ComputedValues {
/// Usage example:
/// let top_color = style.resolve_color(style.Border.border_top_color);
#[inline]
- pub fn resolve_color(&self, color: CSSParserColor) -> RGBA {
- match color {
- CSSParserColor::RGBA(rgba) => rgba,
- CSSParserColor::CurrentColor => self.get_color().color,
- }
+ pub fn resolve_color(&self, color: computed::Color) -> RGBA {
+ color.to_rgba(self.get_color().color)
}
/// Get the logical computed inline size.
@@ -2626,7 +2622,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device,
let ignore_colors = !device.use_document_colors();
let default_background_color_decl = if ignore_colors {
let color = device.default_background_color();
- Some(PropertyDeclaration::BackgroundColor(Color::RGBA(color).into()))
+ Some(PropertyDeclaration::BackgroundColor(color.into()))
} else {
None
};
diff --git a/components/style/properties/shorthand/background.mako.rs b/components/style/properties/shorthand/background.mako.rs
index 36652a73520..3767d80bed9 100644
--- a/components/style/properties/shorthand/background.mako.rs
+++ b/components/style/properties/shorthand/background.mako.rs
@@ -15,7 +15,7 @@
use properties::longhands::background_clip;
use properties::longhands::background_clip::single_value::computed_value::T as Clip;
use properties::longhands::background_origin::single_value::computed_value::T as Origin;
- use values::specified::{CSSColor, Position, PositionComponent};
+ use values::specified::{Color, Position, PositionComponent};
use parser::Parse;
impl From<background_origin::single_value::SpecifiedValue> for background_clip::single_value::SpecifiedValue {
@@ -50,7 +50,7 @@
% endfor
loop {
if background_color.is_none() {
- if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
+ if let Ok(value) = input.try(|i| Color::parse(context, i)) {
background_color = Some(value);
continue
}
@@ -112,7 +112,7 @@
}));
Ok(expanded! {
- background_color: background_color.unwrap_or(CSSColor::transparent()),
+ background_color: background_color.unwrap_or(Color::transparent()),
background_image: background_image,
background_position_x: background_position_x,
background_position_y: background_position_y,
diff --git a/components/style/properties/shorthand/border.mako.rs b/components/style/properties/shorthand/border.mako.rs
index c84549a544f..b5ebe773c66 100644
--- a/components/style/properties/shorthand/border.mako.rs
+++ b/components/style/properties/shorthand/border.mako.rs
@@ -5,7 +5,7 @@
<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import to_rust_ident, ALL_SIDES, PHYSICAL_SIDES, maybe_moz_logical_alias %>
-${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::CSSColor::parse",
+${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::Color::parse",
spec="https://drafts.csswg.org/css-backgrounds/#border-color",
allow_quirks=True)}
@@ -44,10 +44,10 @@ ${helpers.four_sides_shorthand("border-style", "border-%s-style",
pub fn parse_border(context: &ParserContext, input: &mut Parser)
- -> Result<(specified::CSSColor,
+ -> Result<(specified::Color,
specified::BorderStyle,
specified::BorderSideWidth), ()> {
- use values::specified::{CSSColor, BorderStyle, BorderSideWidth};
+ use values::specified::{Color, BorderStyle, BorderSideWidth};
let _unused = context;
let mut color = None;
let mut style = None;
@@ -55,7 +55,7 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser)
let mut any = false;
loop {
if color.is_none() {
- if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
+ if let Ok(value) = input.try(|i| Color::parse(context, i)) {
color = Some(value);
any = true;
continue
@@ -78,7 +78,7 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser)
break
}
if any {
- Ok((color.unwrap_or_else(|| CSSColor::currentcolor()),
+ Ok((color.unwrap_or_else(|| Color::currentcolor()),
style.unwrap_or(BorderStyle::none),
width.unwrap_or(BorderSideWidth::Medium)))
} else {
diff --git a/components/style/properties/shorthand/outline.mako.rs b/components/style/properties/shorthand/outline.mako.rs
index 8a1ab5900da..649651c02d9 100644
--- a/components/style/properties/shorthand/outline.mako.rs
+++ b/components/style/properties/shorthand/outline.mako.rs
@@ -18,7 +18,7 @@
let mut any = false;
loop {
if color.is_none() {
- if let Ok(value) = input.try(|i| specified::CSSColor::parse(context, i)) {
+ if let Ok(value) = input.try(|i| specified::Color::parse(context, i)) {
color = Some(value);
any = true;
continue
diff --git a/components/style/properties/shorthand/serialize.mako.rs b/components/style/properties/shorthand/serialize.mako.rs
index f8c1ef9bc3e..a86704a5488 100644
--- a/components/style/properties/shorthand/serialize.mako.rs
+++ b/components/style/properties/shorthand/serialize.mako.rs
@@ -3,18 +3,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use style_traits::ToCss;
-use values::specified::{BorderStyle, Color, CSSColor};
+use values::specified::{BorderStyle, Color};
use std::fmt;
fn serialize_directional_border<W, I,>(dest: &mut W,
width: &I,
style: &BorderStyle,
- color: &CSSColor)
+ color: &Color)
-> fmt::Result where W: fmt::Write, I: ToCss {
width.to_css(dest)?;
dest.write_str(" ")?;
style.to_css(dest)?;
- if color.parsed != Color::CurrentColor {
+ if *color != Color::CurrentColor {
dest.write_str(" ")?;
color.to_css(dest)?;
}
diff --git a/components/style/properties/shorthand/text.mako.rs b/components/style/properties/shorthand/text.mako.rs
index c5e7ba12c5e..111adb4de1b 100644
--- a/components/style/properties/shorthand/text.mako.rs
+++ b/components/style/properties/shorthand/text.mako.rs
@@ -70,7 +70,7 @@
self.text_decoration_style.to_css(dest)?;
}
- if self.text_decoration_color.parsed != specified::Color::CurrentColor {
+ if *self.text_decoration_color != specified::Color::CurrentColor {
dest.write_str(" ")?;
self.text_decoration_color.to_css(dest)?;
}
diff --git a/components/style/rule_tree/mod.rs b/components/style/rule_tree/mod.rs
index 37e7334b9db..c51f6f94ff7 100644
--- a/components/style/rule_tree/mod.rs
+++ b/components/style/rule_tree/mod.rs
@@ -912,7 +912,6 @@ impl StrongRuleNode {
-> bool
where E: ::dom::TElement
{
- use cssparser::RGBA;
use gecko_bindings::structs::{NS_AUTHOR_SPECIFIED_BACKGROUND, NS_AUTHOR_SPECIFIED_BORDER};
use gecko_bindings::structs::{NS_AUTHOR_SPECIFIED_PADDING, NS_AUTHOR_SPECIFIED_TEXT_SHADOW};
use properties::{CSSWideKeyword, LonghandId, LonghandIdSet};
@@ -1083,7 +1082,7 @@ impl StrongRuleNode {
if properties.contains(id) {
if !author_colors_allowed {
if let PropertyDeclaration::BackgroundColor(ref color) = *declaration {
- return color.parsed == Color::RGBA(RGBA::transparent())
+ return *color == Color::transparent()
}
}
return true
diff --git a/components/style/values/computed/color.rs b/components/style/values/computed/color.rs
new file mode 100644
index 00000000000..8c9a863b2c5
--- /dev/null
+++ b/components/style/values/computed/color.rs
@@ -0,0 +1,144 @@
+/* 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/. */
+
+//! Computed color values.
+
+use cssparser::{Color as CSSParserColor, RGBA};
+use std::fmt;
+use style_traits::ToCss;
+
+/// This struct represents a combined color from a numeric color and
+/// the current foreground color (currentcolor keyword).
+/// Conceptually, the formula is "color * (1 - p) + currentcolor * p"
+/// where p is foreground_ratio.
+#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct Color {
+ /// RGBA color.
+ pub color: RGBA,
+ /// The ratio of currentcolor in complex color.
+ pub foreground_ratio: u8,
+}
+
+fn blend_color_component(bg: u8, fg: u8, fg_alpha: u8) -> u8 {
+ let bg_ratio = (u8::max_value() - fg_alpha) as u32;
+ let fg_ratio = fg_alpha as u32;
+ let color = bg as u32 * bg_ratio + fg as u32 * fg_ratio;
+ // Rounding divide the number by 255
+ ((color + 127) / 255) as u8
+}
+
+impl Color {
+ /// Returns a numeric color representing the given RGBA value.
+ pub fn rgba(rgba: RGBA) -> Color {
+ Color {
+ color: rgba,
+ foreground_ratio: 0,
+ }
+ }
+
+ /// Returns a complex color value representing transparent.
+ pub fn transparent() -> Color {
+ Color::rgba(RGBA::transparent())
+ }
+
+ /// Returns a complex color value representing currentcolor.
+ pub fn currentcolor() -> Color {
+ Color {
+ color: RGBA::transparent(),
+ foreground_ratio: u8::max_value(),
+ }
+ }
+
+ /// Whether it is a numeric color (no currentcolor component).
+ pub fn is_numeric(&self) -> bool {
+ self.foreground_ratio == 0
+ }
+
+ /// Whether it is a currentcolor value (no numeric color component).
+ pub fn is_currentcolor(&self) -> bool {
+ self.foreground_ratio == u8::max_value()
+ }
+
+ /// Combine this complex color with the given foreground color into
+ /// a numeric RGBA color. It currently uses linear blending.
+ pub fn to_rgba(&self, fg_color: RGBA) -> RGBA {
+ // Common cases that the complex color is either pure numeric
+ // color or pure currentcolor.
+ if self.is_numeric() {
+ return self.color;
+ }
+ if self.is_currentcolor() {
+ return fg_color.clone();
+ }
+ // Common case that alpha channel is equal (usually both are opaque).
+ let fg_ratio = self.foreground_ratio;
+ if self.color.alpha == fg_color.alpha {
+ let r = blend_color_component(self.color.red, fg_color.red, fg_ratio);
+ let g = blend_color_component(self.color.green, fg_color.green, fg_ratio);
+ let b = blend_color_component(self.color.blue, fg_color.blue, fg_ratio);
+ return RGBA::new(r, g, b, fg_color.alpha);
+ }
+
+ // For the more complicated case that the alpha value differs,
+ // we use the following formula to compute the components:
+ // alpha = self_alpha * (1 - fg_ratio) + fg_alpha * fg_ratio
+ // color = (self_color * self_alpha * (1 - fg_ratio) +
+ // fg_color * fg_alpha * fg_ratio) / alpha
+
+ let p1 = (1. / 255.) * (255 - fg_ratio) as f32;
+ let a1 = self.color.alpha_f32();
+ let r1 = a1 * self.color.red_f32();
+ let g1 = a1 * self.color.green_f32();
+ let b1 = a1 * self.color.blue_f32();
+
+ let p2 = 1. - p1;
+ let a2 = fg_color.alpha_f32();
+ let r2 = a2 * fg_color.red_f32();
+ let g2 = a2 * fg_color.green_f32();
+ let b2 = a2 * fg_color.blue_f32();
+
+ let a = p1 * a1 + p2 * a2;
+ if a == 0.0 {
+ return RGBA::transparent();
+ }
+
+ let inverse_a = 1. / a;
+ let r = (p1 * r1 + p2 * r2) * inverse_a;
+ let g = (p1 * g1 + p2 * g2) * inverse_a;
+ let b = (p1 * b1 + p2 * b2) * inverse_a;
+ return RGBA::from_floats(r, g, b, a);
+ }
+}
+
+impl PartialEq for Color {
+ fn eq(&self, other: &Color) -> bool {
+ self.foreground_ratio == other.foreground_ratio &&
+ (self.is_currentcolor() || self.color == other.color)
+ }
+}
+
+impl From<RGBA> for Color {
+ fn from(color: RGBA) -> Color {
+ Color {
+ color: color,
+ foreground_ratio: 0,
+ }
+ }
+}
+
+impl ToCss for Color {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ if self.is_numeric() {
+ self.color.to_css(dest)
+ } else if self.is_currentcolor() {
+ CSSParserColor::CurrentColor.to_css(dest)
+ } else {
+ Ok(())
+ }
+ }
+}
+
+/// Computed value type for the specified RGBAColor.
+pub type RGBAColor = RGBA;
diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs
index 5f51dd22f85..3718be2fbd3 100644
--- a/components/style/values/computed/image.rs
+++ b/components/style/values/computed/image.rs
@@ -7,7 +7,7 @@
//!
//! [image]: https://drafts.csswg.org/css-images/#image-values
-use cssparser::Color as CSSColor;
+use cssparser::RGBA;
use std::f32::consts::PI;
use std::fmt;
use style_traits::ToCss;
@@ -35,7 +35,7 @@ pub type Gradient = GenericGradient<
Length,
LengthOrPercentage,
Position,
- CSSColor,
+ RGBA,
>;
/// A computed gradient kind.
@@ -60,10 +60,10 @@ pub enum LineDirection {
pub type EndingShape = GenericEndingShape<Length, LengthOrPercentage>;
/// A computed gradient item.
-pub type GradientItem = GenericGradientItem<CSSColor, LengthOrPercentage>;
+pub type GradientItem = GenericGradientItem<RGBA, LengthOrPercentage>;
/// A computed color stop.
-pub type ColorStop = GenericColorStop<CSSColor, LengthOrPercentage>;
+pub type ColorStop = GenericColorStop<RGBA, LengthOrPercentage>;
/// Computed values for ImageRect.
pub type ImageRect = GenericImageRect<NumberOrPercentage>;
diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs
index 1547cf29424..ff682255d99 100644
--- a/components/style/values/computed/mod.rs
+++ b/components/style/values/computed/mod.rs
@@ -23,11 +23,11 @@ use super::generics::grid::TrackList as GenericTrackList;
use super::specified;
pub use app_units::Au;
-pub use cssparser::Color as CSSColor;
pub use properties::animated_properties::TransitionProperty;
pub use self::background::BackgroundSize;
pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageSideWidth};
pub use self::border::{BorderRadius, BorderCornerRadius};
+pub use self::color::{Color, RGBAColor};
pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect};
#[cfg(feature = "gecko")]
pub use self::gecko::ScrollSnapPoint;
@@ -48,6 +48,7 @@ pub use self::transform::{TimingFunction, TransformOrigin};
pub mod background;
pub mod basic_shape;
pub mod border;
+pub mod color;
pub mod image;
#[cfg(feature = "gecko")]
pub mod gecko;
@@ -360,86 +361,6 @@ impl ToCss for Time {
}
}
-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::System(system) => to_rgba(system.to_computed_value(context)),
- 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),
- specified::Color::InheritFromBodyQuirk => {
- use dom::TElement;
- use gecko::wrapper::GeckoElement;
- use gecko_bindings::bindings::Gecko_GetBody;
- let body = unsafe {
- Gecko_GetBody(pres_context)
- };
- if let Some(body) = body {
- let wrap = GeckoElement(body);
- let borrow = wrap.borrow_data();
- borrow.as_ref().unwrap()
- .styles().primary.values()
- .get_color()
- .clone_color()
- } else {
- to_rgba(pres_context.mDefaultColor)
- }
- },
- }
- }
-
- 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 {
- (match *computed {
- CSSColor::RGBA(rgba) => specified::Color::RGBA(rgba),
- CSSColor::CurrentColor => specified::Color::CurrentColor,
- }).into()
- }
-}
-
#[cfg(feature = "gecko")]
impl ToComputedValue for specified::JustifyItems {
type ComputedValue = JustifyItems;
@@ -480,7 +401,7 @@ pub struct Shadow {
pub offset_y: Au,
pub blur_radius: Au,
pub spread_radius: Au,
- pub color: CSSColor,
+ pub color: Color,
pub inset: bool,
}
@@ -559,9 +480,9 @@ impl IntegerOrAuto {
}
/// Computed SVG Paint value
-pub type SVGPaint = ::values::generics::SVGPaint<CSSColor>;
+pub type SVGPaint = ::values::generics::SVGPaint<RGBA>;
/// Computed SVG Paint Kind value
-pub type SVGPaintKind = ::values::generics::SVGPaintKind<CSSColor>;
+pub type SVGPaintKind = ::values::generics::SVGPaintKind<RGBA>;
impl Default for SVGPaint {
fn default() -> Self {
@@ -577,7 +498,7 @@ impl SVGPaint {
pub fn black() -> Self {
let rgba = RGBA::from_floats(0., 0., 0., 1.);
SVGPaint {
- kind: ::values::generics::SVGPaintKind::Color(CSSColor::RGBA(rgba)),
+ kind: ::values::generics::SVGPaintKind::Color(rgba),
fallback: None,
}
}
@@ -662,4 +583,4 @@ impl ClipRectOrAuto {
}
/// <color> | auto
-pub type ColorOrAuto = Either<CSSColor, Auto>;
+pub type ColorOrAuto = Either<Color, Auto>;
diff --git a/components/style/values/specified/color.rs b/components/style/values/specified/color.rs
index 0599563a494..9fb5e849c5c 100644
--- a/components/style/values/specified/color.rs
+++ b/components/style/values/specified/color.rs
@@ -2,102 +2,336 @@
* 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.
-#[cfg(not(feature = "gecko"))] pub use self::servo::Color;
-#[cfg(feature = "gecko")] pub use self::gecko::Color;
+use cssparser::{Color as CSSParserColor, Parser, RGBA, Token};
+#[cfg(feature = "gecko")]
+use gecko_bindings::structs::nscolor;
+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::{Color as ComputedColor, Context, ToComputedValue};
-#[cfg(not(feature = "gecko"))]
-mod servo {
- pub use cssparser::Color;
- use cssparser::Parser;
- use parser::{Parse, ParserContext};
+/// Specified color value
+#[derive(Clone, PartialEq, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum Color {
+ /// The 'currentColor' keyword
+ CurrentColor,
+ /// A specific RGBA color
+ Numeric {
+ /// Parsed RGBA color
+ parsed: RGBA,
+ /// Authored representation
+ authored: Option<Box<str>>,
+ },
+ /// A complex color value from computed value
+ Complex(ComputedColor),
- 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;
- /// 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),
- /// -moz-default-color
- MozDefaultColor,
- /// -moz-default-background-color
- MozDefaultBackgroundColor,
- /// -moz-hyperlinktext
- MozHyperlinktext,
- /// -moz-activehyperlinktext
- MozActiveHyperlinktext,
- /// -moz-visitedhyperlinktext
- MozVisitedHyperlinktext,
- /// Quirksmode-only rule for inheriting color from the body
- InheritFromBodyQuirk,
- }
-
- no_viewport_percentage!(Color);
-
- impl From<CSSParserColor> for Color {
- fn from(value: CSSParserColor) -> Self {
- match value {
+ define_css_keyword_enum! { SpecialColorKeyword:
+ "-moz-default-color" => MozDefaultColor,
+ "-moz-default-background-color" => MozDefaultBackgroundColor,
+ "-moz-hyperlinktext" => MozHyperlinktext,
+ "-moz-activehyperlinktext" => MozActiveHyperlinktext,
+ "-moz-visitedhyperlinktext" => MozVisitedHyperlinktext,
+ }
+}
+
+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, ()> {
+ // Currently we only store authored value for color keywords,
+ // because all browsers serialize those values as keywords for
+ // specified value.
+ let start_position = input.position();
+ let authored = match input.next() {
+ Ok(Token::Ident(s)) => Some(s.to_lowercase().into_boxed_str()),
+ _ => None,
+ };
+ input.reset(start_position);
+ if let Ok(value) = input.try(CSSParserColor::parse) {
+ Ok(match value {
CSSParserColor::CurrentColor => Color::CurrentColor,
- CSSParserColor::RGBA(x) => Color::RGBA(x),
+ CSSParserColor::RGBA(rgba) => Color::Numeric {
+ parsed: rgba,
+ authored: authored,
+ },
+ })
+ } 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 {
+ Color::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
+ Color::Numeric { authored: Some(ref authored), .. } => dest.write_str(authored),
+ Color::Numeric { parsed: ref rgba, .. } => rgba.to_css(dest),
+ Color::Complex(_) => Ok(()),
+ #[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(()),
+ }
+ }
+}
+
+/// A wrapper of cssparser::Color::parse_hash.
+///
+/// That function should never return CurrentColor, so it makes no sense
+/// to handle a cssparser::Color here. This should really be done in
+/// cssparser directly rather than here.
+fn parse_hash_color(value: &[u8]) -> Result<RGBA, ()> {
+ CSSParserColor::parse_hash(value).map(|color| {
+ match color {
+ CSSParserColor::RGBA(rgba) => rgba,
+ CSSParserColor::CurrentColor =>
+ unreachable!("parse_hash should never return currentcolor"),
+ }
+ })
+}
+
+impl Color {
+ /// Returns currentcolor value.
+ #[inline]
+ pub fn currentcolor() -> Color {
+ Color::CurrentColor
+ }
+
+ /// Returns transparent value.
+ #[inline]
+ pub fn transparent() -> Color {
+ // We should probably set authored to "transparent", but maybe it doesn't matter.
+ Color::rgba(RGBA::transparent())
+ }
+
+ /// Returns a numeric RGBA color value.
+ #[inline]
+ pub fn rgba(rgba: RGBA) -> Self {
+ Color::Numeric {
+ parsed: rgba,
+ authored: None,
+ }
+ }
+
+ /// 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, ()> {
+ input.try(|i| Self::parse(context, i)).or_else(|_| {
+ if !allow_quirks.allowed(context.quirks_mode) {
+ return Err(());
+ }
+ Color::parse_quirky_color(input).map(|rgba| Color::rgba(rgba))
+ })
+ }
- 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 {
- 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(())
+ /// Parse a <quirky-color> value.
+ ///
+ /// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
+ fn parse_quirky_color(input: &mut Parser) -> Result<RGBA, ()> {
+ 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 parse_hash_color(ident.as_bytes());
}
+ _ => {
+ 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);
+ parse_hash_color(&serialization)
+ }
+
+ /// Returns false if the color is completely transparent, and
+ /// true otherwise.
+ pub fn is_non_transparent(&self) -> bool {
+ match *self {
+ Color::Numeric { ref parsed, .. } => parsed.alpha != 0,
+ _ => true,
}
}
+}
+
+#[cfg(feature = "gecko")]
+fn convert_nscolor_to_computedcolor(color: nscolor) -> ComputedColor {
+ use gecko::values::convert_nscolor_to_rgba;
+ ComputedColor::rgba(convert_nscolor_to_rgba(color))
+}
+
+impl ToComputedValue for Color {
+ type ComputedValue = ComputedColor;
- 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::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"),
- Color::InheritFromBodyQuirk => Ok(()),
+ fn to_computed_value(&self, _context: &Context) -> ComputedColor {
+ match *self {
+ Color::CurrentColor => ComputedColor::currentcolor(),
+ Color::Numeric { ref parsed, .. } => ComputedColor::rgba(*parsed),
+ Color::Complex(ref complex) => *complex,
+ #[cfg(feature = "gecko")]
+ Color::System(system) =>
+ convert_nscolor_to_computedcolor(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 };
+ 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 => {
+ 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)
+ };
+ if let Some(body) = body {
+ let wrap = GeckoElement(body);
+ let borrow = wrap.borrow_data();
+ ComputedColor::rgba(borrow.as_ref().unwrap()
+ .styles().primary.values()
+ .get_color()
+ .clone_color())
+ } else {
+ convert_nscolor_to_computedcolor(pres_context.mDefaultColor)
+ }
+ },
+ }
+ }
+
+ fn from_computed_value(computed: &ComputedColor) -> Self {
+ if computed.is_numeric() {
+ Color::rgba(computed.color)
+ } else if computed.is_currentcolor() {
+ Color::currentcolor()
+ } else {
+ Color::Complex(*computed)
}
}
}
+
+/// Specified color value, but resolved to just RGBA for computed value
+/// with value from color property at the same context.
+#[derive(Clone, PartialEq, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct RGBAColor(pub Color);
+
+no_viewport_percentage!(RGBAColor);
+
+impl Parse for RGBAColor {
+ fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ Color::parse(context, input).map(RGBAColor)
+ }
+}
+
+impl ToCss for RGBAColor {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ self.0.to_css(dest)
+ }
+}
+
+impl ToComputedValue for RGBAColor {
+ type ComputedValue = RGBA;
+
+ fn to_computed_value(&self, context: &Context) -> RGBA {
+ self.0.to_computed_value(context)
+ .to_rgba(context.style.get_color().clone_color())
+ }
+
+ fn from_computed_value(computed: &RGBA) -> Self {
+ RGBAColor(Color::rgba(*computed))
+ }
+}
+
+impl From<Color> for RGBAColor {
+ fn from(color: Color) -> RGBAColor {
+ RGBAColor(color)
+ }
+}
diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs
index 4564bc0993f..4284f2f2a43 100644
--- a/components/style/values/specified/image.rs
+++ b/components/style/values/specified/image.rs
@@ -24,8 +24,8 @@ use values::generics::image::{Image as GenericImage, ImageRect as GenericImageRe
use values::generics::image::{LineDirection as GenericsLineDirection, ShapeExtent};
use values::generics::image::PaintWorklet;
use values::generics::position::Position as GenericPosition;
-use values::specified::{Angle, CSSColor, Color, Length, LengthOrPercentage};
-use values::specified::{Number, NumberOrPercentage, Percentage};
+use values::specified::{Angle, Color, Length, LengthOrPercentage};
+use values::specified::{Number, NumberOrPercentage, Percentage, RGBAColor};
use values::specified::position::{Position, PositionComponent, Side, X, Y};
use values::specified::url::SpecifiedUrl;
@@ -43,7 +43,7 @@ pub type Gradient = GenericGradient<
Length,
LengthOrPercentage,
Position,
- CSSColor,
+ RGBAColor,
>;
/// A specified gradient kind.
@@ -72,10 +72,10 @@ pub enum LineDirection {
pub type EndingShape = GenericEndingShape<Length, LengthOrPercentage>;
/// A specified gradient item.
-pub type GradientItem = GenericGradientItem<CSSColor, LengthOrPercentage>;
+pub type GradientItem = GenericGradientItem<RGBAColor, LengthOrPercentage>;
/// A computed color stop.
-pub type ColorStop = GenericColorStop<CSSColor, LengthOrPercentage>;
+pub type ColorStop = GenericColorStop<RGBAColor, LengthOrPercentage>;
/// Specified values for `moz-image-rect`
/// -moz-image-rect(<uri>, top, right, bottom, left);
@@ -386,11 +386,11 @@ impl Gradient {
"to" => 1.,
_ => return Err(()),
};
- let color = CSSColor::parse(context, i)?;
- if color.parsed == Color::CurrentColor {
+ let color = Color::parse(context, i)?;
+ if color == Color::CurrentColor {
return Err(());
}
- Ok((color, p))
+ Ok((color.into(), p))
})?;
if reverse_stops {
p = 1. - p;
@@ -405,11 +405,11 @@ impl Gradient {
if items.is_empty() {
items = vec![
GenericGradientItem::ColorStop(GenericColorStop {
- color: CSSColor::transparent(),
+ color: Color::transparent().into(),
position: Some(Percentage(0.).into()),
}),
GenericGradientItem::ColorStop(GenericColorStop {
- color: CSSColor::transparent(),
+ color: Color::transparent().into(),
position: Some(Percentage(1.).into()),
}),
];
@@ -674,7 +674,7 @@ impl GradientItem {
impl Parse for ColorStop {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Ok(ColorStop {
- color: try!(CSSColor::parse(context, input)),
+ color: try!(RGBAColor::parse(context, input)),
position: input.try(|i| LengthOrPercentage::parse(context, i)).ok(),
})
}
diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs
index 59ff135c303..2ea37db841f 100644
--- a/components/style/values/specified/mod.rs
+++ b/components/style/values/specified/mod.rs
@@ -8,15 +8,13 @@
use Namespace;
use context::QuirksMode;
-use cssparser::{self, Parser, Token, serialize_identifier};
-use itoa;
+use cssparser::{Parser, Token, serialize_identifier};
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::{Color, RGBAColor};
pub use self::rect::LengthOrNumberRect;
#[cfg(feature = "gecko")]
pub use self::gecko::ScrollSnapPoint;
@@ -92,166 +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()
- }
-}
-
-#[derive(Clone, PartialEq, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[allow(missing_docs)]
-pub struct CSSRGBA {
- pub parsed: cssparser::RGBA,
- pub authored: Option<Box<str>>,
-}
-
-no_viewport_percentage!(CSSRGBA);
-
-impl ToCss for CSSRGBA {
- 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),
- }
- }
-}
-
/// Parse an `<integer>` value, handling `calc()` correctly.
pub fn parse_integer(context: &ParserContext, input: &mut Parser) -> Result<Integer, ()> {
match try!(input.next()) {
@@ -843,7 +681,7 @@ pub struct Shadow {
pub offset_y: Length,
pub blur_radius: Length,
pub spread_radius: Length,
- pub color: Option<CSSColor>,
+ pub color: Option<Color>,
pub inset: bool,
}
@@ -857,10 +695,8 @@ impl ToComputedValue for Shadow {
offset_y: self.offset_y.to_computed_value(context),
blur_radius: self.blur_radius.to_computed_value(context),
spread_radius: self.spread_radius.to_computed_value(context),
- color: self.color
- .as_ref()
- .map(|color| color.to_computed_value(context))
- .unwrap_or(cssparser::Color::CurrentColor),
+ color: self.color.as_ref().unwrap_or(&Color::CurrentColor)
+ .to_computed_value(context),
inset: self.inset,
}
}
@@ -933,7 +769,7 @@ impl Shadow {
}
}
if color.is_none() {
- if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
+ if let Ok(value) = input.try(|i| Color::parse(context, i)) {
color = Some(value);
continue
}
@@ -961,10 +797,10 @@ impl Shadow {
no_viewport_percentage!(SVGPaint);
/// Specified SVG Paint value
-pub type SVGPaint = ::values::generics::SVGPaint<CSSColor>;
+pub type SVGPaint = ::values::generics::SVGPaint<RGBAColor>;
/// Specified SVG Paint Kind value
-pub type SVGPaintKind = ::values::generics::SVGPaintKind<CSSColor>;
+pub type SVGPaintKind = ::values::generics::SVGPaintKind<RGBAColor>;
impl ToComputedValue for SVGPaint {
type ComputedValue = super::computed::SVGPaint;
@@ -991,12 +827,7 @@ impl ToComputedValue for SVGPaintKind {
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
- self.convert(|color| {
- match color.parsed {
- Color::CurrentColor => cssparser::Color::RGBA(context.style().get_color().clone_color()),
- _ => color.to_computed_value(context),
- }
- })
+ self.convert(|color| color.to_computed_value(context))
}
#[inline]
@@ -1164,7 +995,7 @@ impl ClipRectOrAuto {
}
/// <color> | auto
-pub type ColorOrAuto = Either<CSSColor, Auto>;
+pub type ColorOrAuto = Either<Color, Auto>;
/// Whether quirks are allowed in this context.
#[derive(Clone, Copy, PartialEq)]
diff --git a/components/style/values/specified/mod.rs.rej b/components/style/values/specified/mod.rs.rej
new file mode 100644
index 00000000000..0136e286c72
--- /dev/null
+++ b/components/style/values/specified/mod.rs.rej
@@ -0,0 +1,44 @@
+--- components/style/values/specified/mod.rs
++++ components/style/values/specified/mod.rs
+@@ -4,40 +4,38 @@
+
+ //! Specified values.
+ //!
+ //! TODO(emilio): Enhance docs.
+
+ 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_};
+ use super::computed::{self, Context};
+ use super::computed::{Shadow as ComputedShadow, ToComputedValue};
+ use super::generics::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
+ use super::generics::grid::TrackList as GenericTrackList;
+ use values::computed::ComputedValueAsSpecified;
+ use values::specified::calc::CalcNode;
+
+ #[cfg(feature = "gecko")]
+ pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
+ 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;
+ pub use super::generics::grid::GridLine;
+ pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
+ pub use self::image::{GradientItem, GradientKind, Image, ImageRect, ImageLayer};
+ pub use self::length::AbsoluteLength;
+ pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage};
+ pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
+ pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength};
diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs
index 6363e38deb1..fa08f50e4db 100644
--- a/ports/geckolib/glue.rs
+++ b/ports/geckolib/glue.rs
@@ -2216,10 +2216,10 @@ pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations:
RawServoDeclarationBlockBorrowed,
property: nsCSSPropertyID) {
use style::properties::{PropertyDeclaration, LonghandId};
- use style::values::specified::{Color, CSSColor};
+ use style::values::specified::Color;
let long = get_longhand_from_id!(property);
- let cc = CSSColor { parsed: Color::CurrentColor, authored: None };
+ let cc = Color::currentcolor();
let prop = match_wrap_declared! { long,
BorderTopColor => cc,
@@ -2240,11 +2240,11 @@ pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations:
use style::gecko::values::convert_nscolor_to_rgba;
use style::properties::{PropertyDeclaration, LonghandId};
use style::properties::longhands;
- use style::values::specified::{Color, CSSColor};
+ use style::values::specified::Color;
let long = get_longhand_from_id!(property);
let rgba = convert_nscolor_to_rgba(value);
- let color = CSSColor { parsed: Color::RGBA(rgba), authored: None };
+ let color = Color::rgba(rgba);
let prop = match_wrap_declared! { long,
BorderTopColor => color,
diff --git a/tests/unit/style/parsing/ui.rs b/tests/unit/style/parsing/ui.rs
index 9347b1fbc01..14d96656b32 100644
--- a/tests/unit/style/parsing/ui.rs
+++ b/tests/unit/style/parsing/ui.rs
@@ -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::Color;
use style_traits::ToCss;
#[test]
@@ -33,13 +33,13 @@ fn test_caret_color() {
let auto = parse_longhand!(caret_color, "auto");
assert_eq!(auto, Either::Second(Auto));
- let blue_color = CSSColor {
- parsed: Color::RGBA(RGBA {
+ let blue_color = Color::Numeric {
+ parsed: RGBA {
red: 0,
green: 0,
blue: 255,
alpha: 255,
- }),
+ },
authored: Some(String::from("blue").into_boxed_str()),
};
diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs
index e8009794a5a..9ee2877101a 100644
--- a/tests/unit/style/properties/serialization.rs
+++ b/tests/unit/style/properties/serialization.rs
@@ -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, Color};
+use style::values::specified::{Length, LengthOrPercentage};
use style::values::specified::{LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent};
use style::values::specified::{NoCalcLength, PositionComponent};
use style::values::specified::position::Y;
@@ -110,10 +110,7 @@ mod shorthand_serialization {
let line = TextDecorationLine::OVERLINE;
let style = TextDecorationStyle::dotted;
- let color = CSSColor {
- parsed: ComputedColor::RGBA(RGBA::new(128, 0, 128, 255)),
- authored: None
- };
+ let color = RGBA::new(128, 0, 128, 255).into();
properties.push(PropertyDeclaration::TextDecorationLine(line));
properties.push(PropertyDeclaration::TextDecorationStyle(style));
@@ -129,7 +126,7 @@ mod shorthand_serialization {
let line = TextDecorationLine::UNDERLINE;
let style = TextDecorationStyle::solid;
- let color = CSSColor::currentcolor();
+ let color = Color::currentcolor();
properties.push(PropertyDeclaration::TextDecorationLine(line));
properties.push(PropertyDeclaration::TextDecorationStyle(style));
@@ -229,10 +226,7 @@ mod shorthand_serialization {
properties.push(PropertyDeclaration::BorderBottomWidth(px_30.clone()));
properties.push(PropertyDeclaration::BorderLeftWidth(px_10.clone()));
- let blue = CSSColor {
- parsed: ComputedColor::RGBA(RGBA::new(0, 0, 255, 255)),
- authored: None
- };
+ let blue = Color::rgba(RGBA::new(0, 0, 255, 255));
properties.push(PropertyDeclaration::BorderTopColor(blue.clone()));
properties.push(PropertyDeclaration::BorderRightColor(blue.clone()));
@@ -262,10 +256,7 @@ mod shorthand_serialization {
properties.push(PropertyDeclaration::BorderBottomWidth(px_30.clone()));
properties.push(PropertyDeclaration::BorderLeftWidth(px_30.clone()));
- let blue = CSSColor {
- parsed: ComputedColor::RGBA(RGBA::new(0, 0, 255, 255)),
- authored: None
- };
+ let blue = Color::rgba(RGBA::new(0, 0, 255, 255));
properties.push(PropertyDeclaration::BorderTopColor(blue.clone()));
properties.push(PropertyDeclaration::BorderRightColor(blue.clone()));
@@ -332,15 +323,8 @@ mod shorthand_serialization {
fn border_color_should_serialize_correctly() {
let mut properties = Vec::new();
- let red = CSSColor {
- parsed: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)),
- authored: None
- };
-
- let blue = CSSColor {
- parsed: ComputedColor::RGBA(RGBA::new(0, 0, 255, 255)),
- authored: None
- };
+ let red = Color::rgba(RGBA::new(255, 0, 0, 255));
+ let blue = Color::rgba(RGBA::new(0, 0, 255, 255));
properties.push(PropertyDeclaration::BorderTopColor(blue.clone()));
properties.push(PropertyDeclaration::BorderRightColor(red.clone()));
@@ -405,10 +389,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)),
- authored: None
- };
+ let color = RGBA::new(255, 0, 0, 255).into();
properties.push(PropertyDeclaration::BorderTopWidth(width));
properties.push(PropertyDeclaration::BorderTopStyle(style));
@@ -418,10 +399,10 @@ mod shorthand_serialization {
assert_eq!(serialization, "border-top: 4px solid rgb(255, 0, 0);");
}
- fn get_border_property_values() -> (BorderSideWidth, BorderStyle, CSSColor) {
+ fn get_border_property_values() -> (BorderSideWidth, BorderStyle, Color) {
(BorderSideWidth::Length(Length::from_px(4f32)),
BorderStyle::solid,
- CSSColor::currentcolor())
+ Color::currentcolor())
}
#[test]
@@ -532,10 +513,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)),
- authored: None
- };
+ let color = RGBA::new(255, 0, 0, 255).into();
properties.push(PropertyDeclaration::OutlineWidth(width));
properties.push(PropertyDeclaration::OutlineStyle(style));
@@ -551,10 +529,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)),
- authored: None
- };
+ let color = RGBA::new(255, 0, 0, 255).into();
properties.push(PropertyDeclaration::OutlineWidth(width));
properties.push(PropertyDeclaration::OutlineStyle(style));
properties.push(PropertyDeclaration::OutlineColor(color));
diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs
index 686a3979a9a..e8967c54c0c 100644
--- a/tests/unit/style/stylesheets.rs
+++ b/tests/unit/style/stylesheets.rs
@@ -158,9 +158,9 @@ fn test_parse_stylesheet() {
)),
block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
(PropertyDeclaration::BackgroundColor(
- longhands::background_color::SpecifiedValue {
+ longhands::background_color::SpecifiedValue::Numeric {
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),
}
),
Importance::Normal),
diff --git a/tests/wpt/metadata-css/cssom-1_dev/html/cssstyledeclaration-csstext.htm.ini b/tests/wpt/metadata-css/cssom-1_dev/html/cssstyledeclaration-csstext.htm.ini
deleted file mode 100644
index 5f750141b21..00000000000
--- a/tests/wpt/metadata-css/cssom-1_dev/html/cssstyledeclaration-csstext.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[cssstyledeclaration-csstext.htm]
- type: testharness
- [uppercase value]
- expected: FAIL
-