Skip to content

Commit

Permalink
Auto merge of #17544 - dadaa:bug1371115, r=<try>
Browse files Browse the repository at this point in the history
Support discrete animations for more Gecko things

<!-- Please describe your changes on the following line: -->
This PR fixes https://bugzilla.mozilla.org/show_bug.cgi?id=1371115

---
<!-- 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

<!-- Either: -->
- [X] There are tests for these changes. Add some tests into dom/animation/test/ of m-c in patch 14. Also, remove test fail annotation from meta in wpt as patch 15.

<!-- 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/17544)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Jul 5, 2017
2 parents 006037f + 1b28d5e commit 42e551f
Show file tree
Hide file tree
Showing 19 changed files with 1,750 additions and 1,474 deletions.
286 changes: 285 additions & 1 deletion components/style/gecko/conversions.rs
Expand Up @@ -14,12 +14,15 @@ use gecko_bindings::bindings::{Gecko_CreateGradient, Gecko_SetGradientImageValue
use gecko_bindings::bindings::{Gecko_InitializeImageCropRect, Gecko_SetImageElement};
use gecko_bindings::structs::{nsCSSUnit, nsStyleCoord_CalcValue, nsStyleImage};
use gecko_bindings::structs::{nsresult, SheetType};
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut};
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
use stylesheets::{Origin, RulesMutateError};
use values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image};
use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
use values::generics::grid::TrackSize;
use values::generics::image::{CompatMode, Image as GenericImage, GradientItem};
use values::generics::rect::Rect;
use values::specified::length::Percentage;
use values::specified::url::SpecifiedUrl;

impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
Expand Down Expand Up @@ -362,6 +365,212 @@ impl nsStyleImage {
Gecko_SetGradientImageValue(self, gecko_gradient);
}
}

/// Converts into Image.
pub unsafe fn into_image(self: &nsStyleImage) -> Option<Image> {
use gecko_bindings::bindings::Gecko_GetImageElement;
use gecko_bindings::structs::nsStyleImageType;
use values::computed::{NumberOrPercentage, ImageRect};

match self.mType {
nsStyleImageType::eStyleImageType_Null => {
None
},
nsStyleImageType::eStyleImageType_Image => {
let url = self.get_image_url();
if self.mCropRect.mPtr.is_null() {
Some(GenericImage::Url(url))
} else {
let ref rect = *self.mCropRect.mPtr;
match (NumberOrPercentage::from_gecko_style_coord(&rect.data_at(0)),
NumberOrPercentage::from_gecko_style_coord(&rect.data_at(1)),
NumberOrPercentage::from_gecko_style_coord(&rect.data_at(2)),
NumberOrPercentage::from_gecko_style_coord(&rect.data_at(3))) {
(Some(top), Some(right), Some(bottom), Some(left)) =>
Some(GenericImage::Rect(ImageRect { url, top, right, bottom, left } )),
_ => {
debug_assert!(false, "mCropRect could not convert to NumberOrPercentage");
None
}
}
}
},
nsStyleImageType::eStyleImageType_Gradient => {
Some(GenericImage::Gradient(self.get_gradient()))
},
nsStyleImageType::eStyleImageType_Element => {
use gecko_string_cache::Atom;
let atom = Gecko_GetImageElement(self);
Some(GenericImage::Element(Atom::from(atom)))
},
x => panic!("Unexpected image type {:?}", x)
}
}

unsafe fn get_image_url(self: &nsStyleImage) -> SpecifiedUrl {
use gecko_bindings::bindings::Gecko_GetURLValue;
let url_value = Gecko_GetURLValue(self);
let mut url = SpecifiedUrl::from_url_value_data(url_value.as_ref().unwrap())
.expect("Could not convert to SpecifiedUrl");
url.build_image_value();
url
}

unsafe fn get_gradient(self: &nsStyleImage) -> Gradient {
use gecko::values::convert_nscolor_to_rgba;
use gecko_bindings::bindings::Gecko_GetGradientImageValue;
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};
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE};
use values::computed::{Length, LengthOrPercentage};
use values::computed::image::LineDirection;
use values::computed::position::Position;
use values::generics::image::{ColorStop, CompatMode, Circle, Ellipse, EndingShape, GradientKind, ShapeExtent};
use values::specified::position::{X, Y};

let gecko_gradient = Gecko_GetGradientImageValue(self).as_ref().unwrap();
let angle = Angle::from_gecko_style_coord(&gecko_gradient.mAngle);
let horizontal_style = LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mBgPosX);
let vertical_style = LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mBgPosY);

let kind = match gecko_gradient.mShape as u32 {
NS_STYLE_GRADIENT_SHAPE_LINEAR => {
let line_direction = match (angle, horizontal_style, vertical_style) {
(Some(a), None, None) => LineDirection::Angle(a),
(None, Some(horizontal), Some(vertical)) => {
let horizontal_as_corner = match horizontal {
LengthOrPercentage::Percentage(percentage) => {
if percentage.0 == 0.0 {
Some(X::Left)
} else if percentage.0 == 1.0 {
Some(X::Right)
} else {
None
}
},
_ => None
};
let vertical_as_corner = match vertical {
LengthOrPercentage::Percentage(percentage) => {
if percentage.0 == 0.0 {
Some(Y::Top)
} else if percentage.0 == 1.0 {
Some(Y::Bottom)
} else {
None
}
},
_ => None
};

match (horizontal_as_corner, vertical_as_corner) {
(Some(hc), Some(vc)) => LineDirection::Corner(hc, vc),
_ => LineDirection::MozPosition(
Some(Position { horizontal, vertical }), None)
}
},
(Some(_), Some(horizontal), Some(vertical)) =>
LineDirection::MozPosition(
Some(Position { horizontal, vertical }), angle),
_ => {
debug_assert!(horizontal_style.is_none() && vertical_style.is_none(),
"Unexpected linear gradient direction");
LineDirection::MozPosition(None, None)
}
};
GradientKind::Linear(line_direction)
},
_ => {
let gecko_size_to_keyword = |gecko_size| {
match gecko_size {
NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE => ShapeExtent::ClosestSide,
NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE => ShapeExtent::FarthestSide,
NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER => ShapeExtent::ClosestCorner,
NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER => ShapeExtent::FarthestCorner,
// FIXME: We should support ShapeExtent::Contain and ShapeExtent::Cover.
// But we can't choose those yet since Gecko does not support both values.
// https://bugzilla.mozilla.org/show_bug.cgi?id=1217664
x => panic!("Found unexpected gecko_size: {:?}", x),
}
};

let shape = match gecko_gradient.mShape as u32 {
NS_STYLE_GRADIENT_SHAPE_CIRCULAR => {
let circle = match gecko_gradient.mSize as u32 {
NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => {
let radius = Length::from_gecko_style_coord(&gecko_gradient.mRadiusX)
.expect("mRadiusX could not convert to Length");
debug_assert_eq!(radius,
Length::from_gecko_style_coord(&gecko_gradient.mRadiusY).unwrap());
Circle::Radius(radius)
},
size => Circle::Extent(gecko_size_to_keyword(size))
};
EndingShape::Circle(circle)
},
NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL => {
let length_percentage_keyword = match gecko_gradient.mSize as u32 {
NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => {
match (LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mRadiusX),
LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mRadiusY)) {
(Some(x), Some(y)) => Ellipse::Radii(x, y),
_ => {
debug_assert!(false,
"mRadiusX, mRadiusY could not convert to LengthOrPercentage");
Ellipse::Radii(LengthOrPercentage::zero(),
LengthOrPercentage::zero())
}
}
},
size => Ellipse::Extent(gecko_size_to_keyword(size))
};
EndingShape::Ellipse(length_percentage_keyword)
},
x => panic!("Found unexpected mShape: {:?}", x),
};

let position = match (horizontal_style, vertical_style) {
(Some(horizontal), Some(vertical)) => Position { horizontal, vertical },
_ => {
debug_assert!(false,
"mRadiusX, mRadiusY could not convert to LengthOrPercentage");
Position {
horizontal: LengthOrPercentage::zero(),
vertical: LengthOrPercentage::zero()
}
}
};

GradientKind::Radial(shape, position, angle)
}
};

let items = gecko_gradient.mStops.iter().map(|ref stop| {
if stop.mIsInterpolationHint {
GradientItem::InterpolationHint(
LengthOrPercentage::from_gecko_style_coord(&stop.mLocation)
.expect("mLocation could not convert to LengthOrPercentage")
)
} else {
GradientItem::ColorStop(ColorStop {
color: convert_nscolor_to_rgba(stop.mColor),
position: LengthOrPercentage::from_gecko_style_coord(&stop.mLocation)
})
}
}).collect();

let compat_mode =
if gecko_gradient.mMozLegacySyntax {
CompatMode::Moz
} else if gecko_gradient.mLegacySyntax {
CompatMode::WebKit
} else {
CompatMode::Modern
};

Gradient { items, repeating: gecko_gradient.mRepeating, kind, compat_mode }
}
}

pub mod basic_shape {
Expand Down Expand Up @@ -584,3 +793,78 @@ impl From<Origin> for SheetType {
}
}
}

impl TrackSize<LengthOrPercentage> {
/// Return TrackSize from given two nsStyleCoord
pub fn from_gecko_style_coords<T: CoordData>(gecko_min: &T, gecko_max: &T) -> Self {
use gecko_bindings::structs::root::nsStyleUnit;
use values::computed::length::LengthOrPercentage;
use values::generics::grid::{TrackBreadth, TrackSize};

if gecko_min.unit() == nsStyleUnit::eStyleUnit_None {
debug_assert!(gecko_max.unit() == nsStyleUnit::eStyleUnit_Coord ||
gecko_max.unit() == nsStyleUnit::eStyleUnit_Percent);
return TrackSize::FitContent(LengthOrPercentage::from_gecko_style_coord(gecko_max)
.expect("gecko_max could not convert to LengthOrPercentage"));
}

let min = TrackBreadth::from_gecko_style_coord(gecko_min)
.expect("gecko_min could not convert to TrackBreadth");
let max = TrackBreadth::from_gecko_style_coord(gecko_max)
.expect("gecko_max could not convert to TrackBreadth");
if min == max {
TrackSize::Breadth(max)
} else {
TrackSize::MinMax(min, max)
}
}

/// Save TrackSize to given gecko fields.
pub fn to_gecko_style_coords<T: CoordDataMut>(&self, gecko_min: &mut T, gecko_max: &mut T) {
use values::generics::grid::TrackSize;

match *self {
TrackSize::FitContent(ref lop) => {
// Gecko sets min value to None and max value to the actual value in fit-content
// https://dxr.mozilla.org/mozilla-central/rev/0eef1d5/layout/style/nsRuleNode.cpp#8221
gecko_min.set_value(CoordDataValue::None);
lop.to_gecko_style_coord(gecko_max);
},
TrackSize::Breadth(ref breadth) => {
// Set the value to both fields if there's one breadth value
// https://dxr.mozilla.org/mozilla-central/rev/0eef1d5/layout/style/nsRuleNode.cpp#8230
breadth.to_gecko_style_coord(gecko_min);
breadth.to_gecko_style_coord(gecko_max);
},
TrackSize::MinMax(ref min, ref max) => {
min.to_gecko_style_coord(gecko_min);
max.to_gecko_style_coord(gecko_max);
},
}
}
}

impl<T> Rect<T> where T: GeckoStyleCoordConvertible {
/// Convert this generic Rect to given Gecko fields.
pub fn to_gecko_rect(&self, sides: &mut ::gecko_bindings::structs::nsStyleSides) {
self.0.to_gecko_style_coord(&mut sides.data_at_mut(0));
self.1.to_gecko_style_coord(&mut sides.data_at_mut(1));
self.2.to_gecko_style_coord(&mut sides.data_at_mut(2));
self.3.to_gecko_style_coord(&mut sides.data_at_mut(3));
}

/// Convert from given Gecko data to generic Rect.
pub fn from_gecko_rect(sides: &::gecko_bindings::structs::nsStyleSides)
-> Option<::values::generics::rect::Rect<T>> {
use values::generics::rect::Rect;

Some(
Rect::new(
T::from_gecko_style_coord(&sides.data_at(0)).expect("coord[0] cound not convert"),
T::from_gecko_style_coord(&sides.data_at(1)).expect("coord[1] cound not convert"),
T::from_gecko_style_coord(&sides.data_at(2)).expect("coord[2] cound not convert"),
T::from_gecko_style_coord(&sides.data_at(3)).expect("coord[3] cound not convert")
)
)
}
}
27 changes: 17 additions & 10 deletions components/style/gecko/generated/bindings.rs
Expand Up @@ -8,6 +8,7 @@ type nsAString_internal = nsAString;
use gecko_bindings::structs::mozilla::css::GridTemplateAreasValue;
use gecko_bindings::structs::mozilla::css::ImageValue;
use gecko_bindings::structs::mozilla::css::URLValue;
use gecko_bindings::structs::mozilla::css::URLValueData;
use gecko_bindings::structs::mozilla::MallocSizeOf;
use gecko_bindings::structs::mozilla::Side;
use gecko_bindings::structs::nsIContent;
Expand Down Expand Up @@ -56,6 +57,7 @@ use gecko_bindings::structs::StyleBasicShape;
use gecko_bindings::structs::StyleBasicShapeType;
use gecko_bindings::structs::StyleShapeSource;
use gecko_bindings::structs::StyleTransition;
use gecko_bindings::structs::nsBorderColors;
use gecko_bindings::structs::nsCSSCounterStyleRule;
use gecko_bindings::structs::nsCSSFontFaceRule;
use gecko_bindings::structs::nsCSSKeyword;
Expand Down Expand Up @@ -853,6 +855,10 @@ extern "C" {
pub fn Gecko_CopyMozBorderColors(aDest: *mut nsStyleBorder,
aSrc: *const nsStyleBorder, aSide: Side);
}
extern "C" {
pub fn Gecko_GetMozBorderColors(aBorder: *const nsStyleBorder,
aSide: Side) -> *const nsBorderColors;
}
extern "C" {
pub fn Gecko_FontFamilyList_Clear(aList: *mut FontFamilyList);
}
Expand Down Expand Up @@ -955,6 +961,17 @@ extern "C" {
legacy_syntax: bool, moz_legacy_syntax: bool,
stops: u32) -> *mut nsStyleGradient;
}
extern "C" {
pub fn Gecko_GetURLValue(image: *const nsStyleImage)
-> *const URLValueData;
}
extern "C" {
pub fn Gecko_GetImageElement(image: *const nsStyleImage) -> *mut nsIAtom;
}
extern "C" {
pub fn Gecko_GetGradientImageValue(image: *const nsStyleImage)
-> *const nsStyleGradient;
}
extern "C" {
pub fn Gecko_SetListStyleImageNone(style_struct: *mut nsStyleList);
}
Expand Down Expand Up @@ -2144,16 +2161,6 @@ extern "C" {
pub fn Servo_StyleRule_GetSelectorCount(rule: RawServoStyleRuleBorrowed,
count: *mut u32);
}
extern "C" {
pub fn Servo_StyleRule_SelectorMatchesElement(arg1:
RawServoStyleRuleBorrowed,
arg2:
RawGeckoElementBorrowed,
index: u32,
pseudo_type:
CSSPseudoElementType)
-> bool;
}
extern "C" {
pub fn Servo_ImportRule_GetHref(rule: RawServoImportRuleBorrowed,
result: *mut nsAString);
Expand Down

0 comments on commit 42e551f

Please sign in to comment.