Auto merge of #14598 - DominoTree:master, r=canaltinova

Fix linear gradient's specified form #13892

<!-- Please describe your changes on the following line: -->
WIP for #13892

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #13892  (github issue number if applicable).

<!-- Either: -->
- [x] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- 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/14598)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-12-16 15:11:29 -08:00 committed by GitHub
commit 9d2b98e6f8
6 changed files with 113 additions and 49 deletions

View file

@ -54,8 +54,8 @@ use style::properties::{self, ServoComputedValues};
use style::properties::style_structs;
use style::servo::restyle_damage::REPAINT;
use style::values::{self, Either, RGBA, computed};
use style::values::computed::{Gradient, GradientKind, LengthOrPercentage, LengthOrPercentageOrAuto};
use style::values::specified::{AngleOrCorner, HorizontalDirection, VerticalDirection};
use style::values::computed::{AngleOrCorner, Gradient, GradientKind, LengthOrPercentage, LengthOrPercentageOrAuto};
use style::values::specified::{HorizontalDirection, VerticalDirection};
use style_traits::cursor::Cursor;
use table_cell::CollapsedBordersForCell;
use webrender_traits::{ColorF, GradientStop};

View file

@ -160,10 +160,9 @@ impl nsStyleImage {
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE};
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE};
use gecko_bindings::structs::nsStyleCoord;
use values::computed::{GradientKind, GradientShape, LengthOrKeyword};
use values::computed::{AngleOrCorner, GradientKind, GradientShape, LengthOrKeyword};
use values::computed::LengthOrPercentageOrKeyword;
use values::specified::{AngleOrCorner, HorizontalDirection};
use values::specified::{SizeKeyword, VerticalDirection};
use values::specified::{HorizontalDirection, SizeKeyword, VerticalDirection};
let stop_count = gradient.stops.len();
if stop_count >= ::std::u32::MAX as usize {

View file

@ -8,11 +8,12 @@
//! [image]: https://drafts.csswg.org/css-images/#image-values
use cssparser::Color as CSSColor;
use std::f32::consts::PI;
use std::fmt;
use style_traits::ToCss;
use values::computed::{Context, Length, LengthOrPercentage, ToComputedValue};
use values::computed::{Angle, Context, Length, LengthOrPercentage, ToComputedValue};
use values::computed::position::Position;
use values::specified::{self, AngleOrCorner, SizeKeyword};
use values::specified::{self, HorizontalDirection, SizeKeyword, VerticalDirection};
use values::specified::url::SpecifiedUrl;
@ -185,7 +186,7 @@ impl ToComputedValue for specified::GradientKind {
fn to_computed_value(&self, context: &Context) -> GradientKind {
match *self {
specified::GradientKind::Linear(angle_or_corner) => {
GradientKind::Linear(angle_or_corner)
GradientKind::Linear(angle_or_corner.to_computed_value(context))
},
specified::GradientKind::Radial(ref shape, position) => {
GradientKind::Radial(shape.to_computed_value(context),
@ -454,3 +455,75 @@ impl ToComputedValue for specified::LengthOrPercentageOrKeyword {
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum AngleOrCorner {
Angle(Angle),
Corner(HorizontalDirection, VerticalDirection)
}
impl ToComputedValue for specified::AngleOrCorner {
type ComputedValue = AngleOrCorner;
#[inline]
fn to_computed_value(&self, _: &Context) -> AngleOrCorner {
match *self {
specified::AngleOrCorner::None => {
AngleOrCorner::Angle(Angle(0.0))
},
specified::AngleOrCorner::Angle(angle) => {
AngleOrCorner::Angle(angle)
},
specified::AngleOrCorner::Corner(horizontal, vertical) => {
match (horizontal, vertical) {
(None, Some(VerticalDirection::Top)) => {
AngleOrCorner::Angle(Angle(0.0))
},
(Some(HorizontalDirection::Right), None) => {
AngleOrCorner::Angle(Angle(PI * 0.5))
},
(None, Some(VerticalDirection::Bottom)) => {
AngleOrCorner::Angle(Angle(PI))
},
(Some(HorizontalDirection::Left), None) => {
AngleOrCorner::Angle(Angle(PI * 1.5))
},
(Some(horizontal), Some(vertical)) => {
AngleOrCorner::Corner(horizontal, vertical)
},
(None, None) => {
unreachable!()
}
}
}
}
}
#[inline]
fn from_computed_value(computed: &AngleOrCorner) -> Self {
match *computed {
AngleOrCorner::Angle(angle) => {
specified::AngleOrCorner::Angle(angle)
},
AngleOrCorner::Corner(horizontal, vertical) => {
specified::AngleOrCorner::Corner(Some(horizontal), Some(vertical))
}
}
}
}
impl ToCss for AngleOrCorner {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
AngleOrCorner::Angle(angle) => angle.to_css(dest),
AngleOrCorner::Corner(horizontal, vertical) => {
try!(dest.write_str("to "));
try!(horizontal.to_css(dest));
try!(dest.write_str(" "));
try!(vertical.to_css(dest));
Ok(())
}
}
}
}

View file

@ -11,7 +11,7 @@ use style_traits::ToCss;
use super::{CSSFloat, specified};
pub use cssparser::Color as CSSColor;
pub use self::image::{EndingShape as GradientShape, Gradient, GradientKind, Image};
pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image};
pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
pub use super::{Either, None_};
pub use super::specified::{Angle, BorderStyle, GridLine, Time, UrlOrNone};

View file

@ -10,10 +10,8 @@
use cssparser::Parser;
use parser::{Parse, ParserContext};
use servo_url::ServoUrl;
use std::f32::consts::PI;
use std::fmt;
use style_traits::ToCss;
use values::computed::ComputedValueAsSpecified;
use values::specified::{Angle, CSSColor, Length, LengthOrPercentage};
use values::specified::position::Position;
use values::specified::url::{SpecifiedUrl, UrlExtraData};
@ -70,10 +68,14 @@ impl ToCss for Gradient {
if self.repeating {
try!(dest.write_str("repeating-"));
}
let mut skipcomma = false;
match self.gradient_kind {
GradientKind::Linear(angle_or_corner) => {
try!(dest.write_str("linear-gradient("));
try!(angle_or_corner.to_css(dest));
if angle_or_corner == AngleOrCorner::None {
skipcomma = true;
}
},
GradientKind::Radial(ref shape, position) => {
try!(dest.write_str("radial-gradient("));
@ -83,7 +85,11 @@ impl ToCss for Gradient {
},
}
for stop in &self.stops {
if !skipcomma {
try!(dest.write_str(", "));
} else {
skipcomma = false;
}
try!(stop.to_css(dest));
}
dest.write_str(")")
@ -230,18 +236,28 @@ fn parse_position(context: &ParserContext, input: &mut Parser) -> Result<Positio
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum AngleOrCorner {
Angle(Angle),
Corner(HorizontalDirection, VerticalDirection),
Corner(Option<HorizontalDirection>, Option<VerticalDirection>),
None,
}
impl ToCss for AngleOrCorner {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
AngleOrCorner::None => Ok(()),
AngleOrCorner::Angle(angle) => angle.to_css(dest),
AngleOrCorner::Corner(horizontal, vertical) => {
try!(dest.write_str("to "));
let mut horizontal_present = false;
if let Some(horizontal) = horizontal {
try!(horizontal.to_css(dest));
horizontal_present = true;
}
if let Some(vertical) = vertical {
if horizontal_present {
try!(dest.write_str(" "));
}
try!(vertical.to_css(dest));
}
Ok(())
}
}
@ -259,35 +275,16 @@ impl Parse for AngleOrCorner {
(input.try(HorizontalDirection::parse).ok(), Some(value))
};
try!(input.expect_comma());
match (horizontal, vertical) {
(None, Some(VerticalDirection::Top)) => {
Ok(AngleOrCorner::Angle(Angle(0.0)))
},
(Some(HorizontalDirection::Right), None) => {
Ok(AngleOrCorner::Angle(Angle(PI * 0.5)))
},
(None, Some(VerticalDirection::Bottom)) => {
Ok(AngleOrCorner::Angle(Angle(PI)))
},
(Some(HorizontalDirection::Left), None) => {
Ok(AngleOrCorner::Angle(Angle(PI * 1.5)))
},
(Some(horizontal), Some(vertical)) => {
Ok(AngleOrCorner::Corner(horizontal, vertical))
}
(None, None) => unreachable!(),
}
} else if let Ok(angle) = input.try(|i| Angle::parse(context, i)) {
try!(input.expect_comma());
Ok(AngleOrCorner::Angle(angle))
} else {
Ok(AngleOrCorner::Angle(Angle(PI)))
Ok(AngleOrCorner::None)
}
}
}
impl ComputedValueAsSpecified for AngleOrCorner {}
/// Specified values for one color stop in a linear gradient.
/// https://drafts.csswg.org/css-images/#typedef-color-stop-list
#[derive(Clone, PartialEq, Debug)]

View file

@ -12,12 +12,10 @@ use style_traits::ToCss;
#[test]
fn test_linear_gradient() {
// Parsing from the right
assert_roundtrip_with_context!(Image::parse, "linear-gradient(to left, red, green)",
"linear-gradient(4.712389rad, red, green)");
assert_roundtrip_with_context!(Image::parse, "linear-gradient(to left, red, green)");
// Parsing from the left
assert_roundtrip_with_context!(Image::parse, "linear-gradient(to right, red, green)",
"linear-gradient(1.5707964rad, red, green)");
assert_roundtrip_with_context!(Image::parse, "linear-gradient(to right, red, green)");
// Parsing with two values for <side-or-corner>
assert_roundtrip_with_context!(Image::parse, "linear-gradient(to right top, red, green)");
@ -27,16 +25,13 @@ fn test_linear_gradient() {
"linear-gradient(0.7853982rad, red, green)");
// Parsing with more than two entries in <color-stop-list>
assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, yellow, green)",
"linear-gradient(3.1415927rad, red, yellow, green)");
assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, yellow, green)");
// Parsing with percentage in the <color-stop-list>
assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, green, yellow 50%)",
"linear-gradient(3.1415927rad, red, green, yellow 50%)");
assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, green, yellow 50%)");
// Parsing without <angle> and <side-or-corner>
assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, green)",
"linear-gradient(3.1415927rad, red, green)");
assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, green)");
}
#[test]