mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Add separate computed Color value.
This commit is contained in:
parent
742c45f859
commit
c62935577a
20 changed files with 317 additions and 145 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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"}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::computed::Color as ComputedColor;
|
||||
|
||||
impl From<nscolor> for StyleComplexColor {
|
||||
fn from(other: nscolor) -> Self {
|
||||
|
@ -39,13 +39,12 @@ 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,17 +61,12 @@ impl From<StyleComplexColor> for values::computed::ColorOrAuto {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<StyleComplexColor> for cssparser::Color {
|
||||
impl From<StyleComplexColor> for ComputedColor {
|
||||
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
|
||||
} else {
|
||||
// FIXME #13546 handle interpolation values
|
||||
Color::CurrentColor
|
||||
debug_assert!(!other.mIsAuto);
|
||||
ComputedColor {
|
||||
color: convert_nscolor_to_rgba(other.mColor),
|
||||
foreground_ratio: other.mForegroundRatio,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,37 +2835,41 @@ 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<% data.new_style_struct("Background", inherited=False) %>
|
||||
|
||||
${helpers.predefined_type("background-color", "Color",
|
||||
"::cssparser::Color::RGBA(::cssparser::RGBA::transparent())",
|
||||
"computed_value::T::transparent()",
|
||||
initial_specified_value="SpecifiedValue::transparent()",
|
||||
spec="https://drafts.csswg.org/css-backgrounds/#background-color",
|
||||
animation_value_type="IntermediateColor",
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
%>
|
||||
% for side in ALL_SIDES:
|
||||
${helpers.predefined_type("border-%s-color" % side[0], "Color",
|
||||
"::cssparser::Color::CurrentColor",
|
||||
"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",
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
animation_value_type="IntermediateRGBA"
|
||||
ignored_when_colors_disabled="True"
|
||||
spec="https://drafts.csswg.org/css-color/#color">
|
||||
use cssparser::{Color as CSSParserColor, RGBA};
|
||||
use cssparser::RGBA;
|
||||
use values::specified::{AllowQuirks, Color};
|
||||
|
||||
impl ToComputedValue for SpecifiedValue {
|
||||
|
@ -20,11 +20,8 @@
|
|||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||
match self.0.to_computed_value(context) {
|
||||
CSSParserColor::RGBA(rgba) => rgba,
|
||||
CSSParserColor::CurrentColor =>
|
||||
context.inherited_style.get_color().clone_color(),
|
||||
}
|
||||
self.0.to_computed_value(context)
|
||||
.to_rgba(context.inherited_style.get_color().clone_color())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -52,7 +52,7 @@ ${helpers.predefined_type("column-rule-width",
|
|||
|
||||
// https://drafts.csswg.org/css-multicol-1/#crc
|
||||
${helpers.predefined_type("column-rule-color", "Color",
|
||||
"::cssparser::Color::CurrentColor",
|
||||
"computed_value::T::currentcolor()",
|
||||
initial_specified_value="specified::Color::currentcolor()",
|
||||
products="gecko", animation_value_type="IntermediateColor", extra_prefixes="moz",
|
||||
need_clone=True, ignored_when_colors_disabled=True,
|
||||
|
|
|
@ -686,7 +686,7 @@ ${helpers.predefined_type("word-spacing",
|
|||
</%helpers:longhand>
|
||||
|
||||
${helpers.predefined_type("text-emphasis-color", "Color",
|
||||
"::cssparser::Color::CurrentColor",
|
||||
"computed_value::T::currentcolor()",
|
||||
initial_specified_value="specified::Color::currentcolor()",
|
||||
products="gecko", animation_value_type="IntermediateColor",
|
||||
need_clone=True, ignored_when_colors_disabled=True,
|
||||
|
@ -705,14 +705,14 @@ ${helpers.predefined_type(
|
|||
// https://compat.spec.whatwg.org
|
||||
${helpers.predefined_type(
|
||||
"-webkit-text-fill-color", "Color",
|
||||
"CSSParserColor::CurrentColor",
|
||||
"computed_value::T::currentcolor()",
|
||||
products="gecko", animation_value_type="IntermediateColor",
|
||||
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", "Color",
|
||||
"CSSParserColor::CurrentColor",
|
||||
"computed_value::T::currentcolor()",
|
||||
initial_specified_value="specified::Color::currentcolor()",
|
||||
products="gecko", animation_value_type="IntermediateColor",
|
||||
need_clone=True, ignored_when_colors_disabled=True,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
additional_methods=[Method("outline_has_nonzero_width", "bool")]) %>
|
||||
|
||||
// TODO(pcwalton): `invert`
|
||||
${helpers.predefined_type("outline-color", "Color", "computed::Color::CurrentColor",
|
||||
${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,
|
||||
|
|
|
@ -279,7 +279,7 @@ ${helpers.single_keyword("text-decoration-style",
|
|||
|
||||
${helpers.predefined_type(
|
||||
"text-decoration-color", "Color",
|
||||
"computed::Color::CurrentColor",
|
||||
"computed_value::T::currentcolor()",
|
||||
initial_specified_value="specified::Color::currentcolor()",
|
||||
products="gecko",
|
||||
animation_value_type="IntermediateColor",
|
||||
|
|
|
@ -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;
|
||||
|
@ -1937,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.
|
||||
|
|
|
@ -4,7 +4,141 @@
|
|||
|
||||
//! Computed color values.
|
||||
|
||||
use cssparser::RGBA;
|
||||
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;
|
||||
|
|
|
@ -23,12 +23,11 @@ use super::generics::grid::TrackList as GenericTrackList;
|
|||
use super::specified;
|
||||
|
||||
pub use app_units::Au;
|
||||
pub use cssparser::Color;
|
||||
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::RGBAColor;
|
||||
pub use self::color::{Color, RGBAColor};
|
||||
pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect};
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use self::gecko::ScrollSnapPoint;
|
||||
|
|
|
@ -15,7 +15,7 @@ use std::fmt;
|
|||
use std::io::Write;
|
||||
use style_traits::ToCss;
|
||||
use super::AllowQuirks;
|
||||
use values::computed::{Context, ToComputedValue};
|
||||
use values::computed::{Color as ComputedColor, Context, ToComputedValue};
|
||||
|
||||
/// Specified color value
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
|
@ -30,6 +30,8 @@ pub enum Color {
|
|||
/// Authored representation
|
||||
authored: Option<Box<str>>,
|
||||
},
|
||||
/// A complex color value from computed value
|
||||
Complex(ComputedColor),
|
||||
|
||||
/// A system color
|
||||
#[cfg(feature = "gecko")]
|
||||
|
@ -103,6 +105,7 @@ impl ToCss for Color {
|
|||
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")]
|
||||
|
@ -232,25 +235,27 @@ impl Color {
|
|||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
fn to_rgba(color: nscolor) -> CSSParserColor {
|
||||
fn convert_nscolor_to_computedcolor(color: nscolor) -> ComputedColor {
|
||||
use gecko::values::convert_nscolor_to_rgba;
|
||||
CSSParserColor::RGBA(convert_nscolor_to_rgba(color))
|
||||
ComputedColor::rgba(convert_nscolor_to_rgba(color))
|
||||
}
|
||||
|
||||
impl ToComputedValue for Color {
|
||||
type ComputedValue = CSSParserColor;
|
||||
type ComputedValue = ComputedColor;
|
||||
|
||||
fn to_computed_value(&self, _context: &Context) -> CSSParserColor {
|
||||
fn to_computed_value(&self, _context: &Context) -> ComputedColor {
|
||||
match *self {
|
||||
Color::CurrentColor => CSSParserColor::CurrentColor,
|
||||
Color::Numeric { ref parsed, .. } => CSSParserColor::RGBA(*parsed),
|
||||
Color::CurrentColor => ComputedColor::currentcolor(),
|
||||
Color::Numeric { ref parsed, .. } => ComputedColor::rgba(*parsed),
|
||||
Color::Complex(ref complex) => *complex,
|
||||
#[cfg(feature = "gecko")]
|
||||
Color::System(system) => to_rgba(system.to_computed_value(_context)),
|
||||
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 };
|
||||
to_rgba(match special {
|
||||
convert_nscolor_to_computedcolor(match special {
|
||||
Keyword::MozDefaultColor => pres_context.mDefaultColor,
|
||||
Keyword::MozDefaultBackgroundColor => pres_context.mBackgroundColor,
|
||||
Keyword::MozHyperlinktext => pres_context.mLinkColor,
|
||||
|
@ -270,21 +275,24 @@ impl ToComputedValue for Color {
|
|||
if let Some(body) = body {
|
||||
let wrap = GeckoElement(body);
|
||||
let borrow = wrap.borrow_data();
|
||||
CSSParserColor::RGBA(borrow.as_ref().unwrap()
|
||||
ComputedColor::rgba(borrow.as_ref().unwrap()
|
||||
.styles().primary.values()
|
||||
.get_color()
|
||||
.clone_color())
|
||||
} else {
|
||||
to_rgba(pres_context.mDefaultColor)
|
||||
convert_nscolor_to_computedcolor(pres_context.mDefaultColor)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn from_computed_value(computed: &CSSParserColor) -> Self {
|
||||
match *computed {
|
||||
CSSParserColor::RGBA(rgba) => Color::rgba(rgba),
|
||||
CSSParserColor::CurrentColor => Color::currentcolor(),
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -313,10 +321,8 @@ impl ToComputedValue for RGBAColor {
|
|||
type ComputedValue = RGBA;
|
||||
|
||||
fn to_computed_value(&self, context: &Context) -> RGBA {
|
||||
match self.0.to_computed_value(context) {
|
||||
CSSParserColor::RGBA(rgba) => rgba,
|
||||
CSSParserColor::CurrentColor => context.style.get_color().clone_color(),
|
||||
}
|
||||
self.0.to_computed_value(context)
|
||||
.to_rgba(context.style.get_color().clone_color())
|
||||
}
|
||||
|
||||
fn from_computed_value(computed: &RGBA) -> Self {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
use Namespace;
|
||||
use context::QuirksMode;
|
||||
use cssparser::{self, Parser, Token, serialize_identifier};
|
||||
use cssparser::{Parser, Token, serialize_identifier};
|
||||
use parser::{ParserContext, Parse};
|
||||
use self::grid::TrackSizeOrRepeat;
|
||||
use self::url::SpecifiedUrl;
|
||||
|
@ -695,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,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue