Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support interpolation between currentcolor and numeric color #17219

Merged
merged 10 commits into from Jun 8, 2017

Add separate computed Color value.

  • Loading branch information
upsuper committed Jun 8, 2017
commit c62935577a36ea98c9d625747cc3e4387ee9941e

Some generated files are not rendered by default. Learn more.

@@ -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,
};

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.