mirror of
https://github.com/servo/servo.git
synced 2025-07-03 05:23:38 +01:00
Auto merge of #20871 - emilio:gecko-sync, r=emilio
style: Sync changes from mozilla-central. See each individual commit for details.
This commit is contained in:
commit
11edbfc159
37 changed files with 708 additions and 738 deletions
|
@ -1533,8 +1533,9 @@ impl<'a, ConcreteThreadSafeLayoutNode> PostorderNodeMutTraversal<ConcreteThreadS
|
||||||
|
|
||||||
let style = node.style(self.style_context());
|
let style = node.style(self.style_context());
|
||||||
|
|
||||||
// Bail out if this node has an ancestor with display: none.
|
// Bail out if this node is display: none. The style system guarantees
|
||||||
if style.is_in_display_none_subtree() {
|
// that we don't arrive here for children of those.
|
||||||
|
if style.get_box().display.is_none() {
|
||||||
self.set_flow_construction_result(node, ConstructionResult::None);
|
self.set_flow_construction_result(node, ConstructionResult::None);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,11 @@ use style::computed_values::background_origin::single_value::T as BackgroundOrig
|
||||||
use style::computed_values::border_image_outset::T as BorderImageOutset;
|
use style::computed_values::border_image_outset::T as BorderImageOutset;
|
||||||
use style::properties::style_structs::{self, Background};
|
use style::properties::style_structs::{self, Background};
|
||||||
use style::values::Either;
|
use style::values::Either;
|
||||||
use style::values::computed::{Angle, GradientItem};
|
use style::values::computed::{Angle, GradientItem, BackgroundSize as ComputedBackgroundSize};
|
||||||
use style::values::computed::{LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
use style::values::computed::{LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
use style::values::computed::{NumberOrPercentage, Percentage, Position};
|
use style::values::computed::{NumberOrPercentage, Percentage, Position};
|
||||||
use style::values::computed::image::{EndingShape, LineDirection};
|
use style::values::computed::image::{EndingShape, LineDirection};
|
||||||
|
use style::values::generics::NonNegative;
|
||||||
use style::values::generics::background::BackgroundSize;
|
use style::values::generics::background::BackgroundSize;
|
||||||
use style::values::generics::image::{Circle, Ellipse, ShapeExtent};
|
use style::values::generics::image::{Circle, Ellipse, ShapeExtent};
|
||||||
use style::values::generics::image::EndingShape as GenericEndingShape;
|
use style::values::generics::image::EndingShape as GenericEndingShape;
|
||||||
|
@ -91,7 +92,7 @@ pub fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
|
||||||
/// For a given area and an image compute how big the
|
/// For a given area and an image compute how big the
|
||||||
/// image should be displayed on the background.
|
/// image should be displayed on the background.
|
||||||
fn compute_background_image_size(
|
fn compute_background_image_size(
|
||||||
bg_size: BackgroundSize<LengthOrPercentageOrAuto>,
|
bg_size: ComputedBackgroundSize,
|
||||||
bounds_size: Size2D<Au>,
|
bounds_size: Size2D<Au>,
|
||||||
intrinsic_size: Option<Size2D<Au>>,
|
intrinsic_size: Option<Size2D<Au>>,
|
||||||
) -> Size2D<Au> {
|
) -> Size2D<Au> {
|
||||||
|
@ -99,9 +100,9 @@ fn compute_background_image_size(
|
||||||
None => match bg_size {
|
None => match bg_size {
|
||||||
BackgroundSize::Cover | BackgroundSize::Contain => bounds_size,
|
BackgroundSize::Cover | BackgroundSize::Contain => bounds_size,
|
||||||
BackgroundSize::Explicit { width, height } => Size2D::new(
|
BackgroundSize::Explicit { width, height } => Size2D::new(
|
||||||
MaybeAuto::from_style(width, bounds_size.width)
|
MaybeAuto::from_style(width.0, bounds_size.width)
|
||||||
.specified_or_default(bounds_size.width),
|
.specified_or_default(bounds_size.width),
|
||||||
MaybeAuto::from_style(height, bounds_size.height)
|
MaybeAuto::from_style(height.0, bounds_size.height)
|
||||||
.specified_or_default(bounds_size.height),
|
.specified_or_default(bounds_size.height),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -123,29 +124,29 @@ fn compute_background_image_size(
|
||||||
(
|
(
|
||||||
BackgroundSize::Explicit {
|
BackgroundSize::Explicit {
|
||||||
width,
|
width,
|
||||||
height: LengthOrPercentageOrAuto::Auto,
|
height: NonNegative(LengthOrPercentageOrAuto::Auto),
|
||||||
},
|
},
|
||||||
_,
|
_,
|
||||||
) => {
|
) => {
|
||||||
let width = MaybeAuto::from_style(width, bounds_size.width)
|
let width = MaybeAuto::from_style(width.0, bounds_size.width)
|
||||||
.specified_or_default(own_size.width);
|
.specified_or_default(own_size.width);
|
||||||
Size2D::new(width, width.scale_by(image_aspect_ratio.recip()))
|
Size2D::new(width, width.scale_by(image_aspect_ratio.recip()))
|
||||||
},
|
},
|
||||||
(
|
(
|
||||||
BackgroundSize::Explicit {
|
BackgroundSize::Explicit {
|
||||||
width: LengthOrPercentageOrAuto::Auto,
|
width: NonNegative(LengthOrPercentageOrAuto::Auto),
|
||||||
height,
|
height,
|
||||||
},
|
},
|
||||||
_,
|
_,
|
||||||
) => {
|
) => {
|
||||||
let height = MaybeAuto::from_style(height, bounds_size.height)
|
let height = MaybeAuto::from_style(height.0, bounds_size.height)
|
||||||
.specified_or_default(own_size.height);
|
.specified_or_default(own_size.height);
|
||||||
Size2D::new(height.scale_by(image_aspect_ratio), height)
|
Size2D::new(height.scale_by(image_aspect_ratio), height)
|
||||||
},
|
},
|
||||||
(BackgroundSize::Explicit { width, height }, _) => Size2D::new(
|
(BackgroundSize::Explicit { width, height }, _) => Size2D::new(
|
||||||
MaybeAuto::from_style(width, bounds_size.width)
|
MaybeAuto::from_style(width.0, bounds_size.width)
|
||||||
.specified_or_default(own_size.width),
|
.specified_or_default(own_size.width),
|
||||||
MaybeAuto::from_style(height, bounds_size.height)
|
MaybeAuto::from_style(height.0, bounds_size.height)
|
||||||
.specified_or_default(own_size.height),
|
.specified_or_default(own_size.height),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -916,9 +916,9 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
get_cyclic(&style.get_background().background_size.0, i).clone();
|
get_cyclic(&style.get_background().background_size.0, i).clone();
|
||||||
let size = match background_size {
|
let size = match background_size {
|
||||||
BackgroundSize::Explicit { width, height } => Size2D::new(
|
BackgroundSize::Explicit { width, height } => Size2D::new(
|
||||||
MaybeAuto::from_style(width, bounding_box_size.width)
|
MaybeAuto::from_style(width.0, bounding_box_size.width)
|
||||||
.specified_or_default(bounding_box_size.width),
|
.specified_or_default(bounding_box_size.width),
|
||||||
MaybeAuto::from_style(height, bounding_box_size.height)
|
MaybeAuto::from_style(height.0, bounding_box_size.height)
|
||||||
.specified_or_default(bounding_box_size.height),
|
.specified_or_default(bounding_box_size.height),
|
||||||
),
|
),
|
||||||
_ => bounding_box_size,
|
_ => bounding_box_size,
|
||||||
|
|
|
@ -135,14 +135,17 @@ pub trait TDocument: Sized + Copy + Clone {
|
||||||
fn quirks_mode(&self) -> QuirksMode;
|
fn quirks_mode(&self) -> QuirksMode;
|
||||||
|
|
||||||
/// Get a list of elements with a given ID in this document, sorted by
|
/// Get a list of elements with a given ID in this document, sorted by
|
||||||
/// document position.
|
/// tree position.
|
||||||
///
|
///
|
||||||
/// Can return an error to signal that this list is not available, or also
|
/// Can return an error to signal that this list is not available, or also
|
||||||
/// return an empty slice.
|
/// return an empty slice.
|
||||||
fn elements_with_id(
|
fn elements_with_id<'a>(
|
||||||
&self,
|
&self,
|
||||||
_id: &Atom,
|
_id: &Atom,
|
||||||
) -> Result<&[<Self::ConcreteNode as TNode>::ConcreteElement], ()> {
|
) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
{
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -342,6 +345,21 @@ pub trait TShadowRoot: Sized + Copy + Clone + PartialEq {
|
||||||
fn style_data<'a>(&self) -> &'a CascadeData
|
fn style_data<'a>(&self) -> &'a CascadeData
|
||||||
where
|
where
|
||||||
Self: 'a;
|
Self: 'a;
|
||||||
|
|
||||||
|
/// Get a list of elements with a given ID in this shadow root, sorted by
|
||||||
|
/// tree position.
|
||||||
|
///
|
||||||
|
/// Can return an error to signal that this list is not available, or also
|
||||||
|
/// return an empty slice.
|
||||||
|
fn elements_with_id<'a>(
|
||||||
|
&self,
|
||||||
|
_id: &Atom,
|
||||||
|
) -> Result<&'a [<Self::ConcreteNode as TNode>::ConcreteElement], ()>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
{
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The element trait, the main abstraction the style crate acts over.
|
/// The element trait, the main abstraction the style crate acts over.
|
||||||
|
|
|
@ -221,14 +221,31 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether a given element is descendant of a given `root` node.
|
/// Returns whether a given element connected to `root` is descendant of `root`.
|
||||||
///
|
///
|
||||||
/// NOTE(emilio): if root == element, this returns false.
|
/// NOTE(emilio): if root == element, this returns false.
|
||||||
fn element_is_descendant_of<E>(element: E, root: E::ConcreteNode) -> bool
|
fn connected_element_is_descendant_of<E>(element: E, root: E::ConcreteNode) -> bool
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
{
|
{
|
||||||
if element.as_node().is_in_document() && root == root.owner_doc().as_node() {
|
// Optimize for when the root is a document or a shadow root and the element
|
||||||
|
// is connected to that root.
|
||||||
|
if root.as_document().is_some() {
|
||||||
|
debug_assert!(element.as_node().is_in_document(), "Not connected?");
|
||||||
|
debug_assert_eq!(
|
||||||
|
root,
|
||||||
|
root.owner_doc().as_node(),
|
||||||
|
"Where did this element come from?",
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if root.as_shadow_root().is_some() {
|
||||||
|
debug_assert_eq!(
|
||||||
|
element.containing_shadow().unwrap().as_node(),
|
||||||
|
root,
|
||||||
|
"Not connected?"
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,28 +261,33 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fast path for iterating over every element with a given id in the document
|
/// Fast path for iterating over every element with a given id in the document
|
||||||
/// that `root` is connected to.
|
/// or shadow root that `root` is connected to.
|
||||||
fn fast_connected_elements_with_id<'a, D>(
|
fn fast_connected_elements_with_id<'a, N>(
|
||||||
doc: &'a D,
|
root: N,
|
||||||
root: D::ConcreteNode,
|
|
||||||
id: &Atom,
|
id: &Atom,
|
||||||
quirks_mode: QuirksMode,
|
quirks_mode: QuirksMode,
|
||||||
) -> Result<&'a [<D::ConcreteNode as TNode>::ConcreteElement], ()>
|
) -> Result<&'a [N::ConcreteElement], ()>
|
||||||
where
|
where
|
||||||
D: TDocument,
|
N: TNode + 'a,
|
||||||
{
|
{
|
||||||
debug_assert_eq!(root.owner_doc().as_node(), doc.as_node());
|
|
||||||
|
|
||||||
let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
|
let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
|
||||||
if case_sensitivity != CaseSensitivity::CaseSensitive {
|
if case_sensitivity != CaseSensitivity::CaseSensitive {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !root.is_in_document() {
|
if root.is_in_document() {
|
||||||
return Err(());
|
return root.owner_doc().elements_with_id(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
doc.elements_with_id(id)
|
if let Some(shadow) = root.as_shadow_root() {
|
||||||
|
return shadow.elements_with_id(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(shadow) = root.as_element().and_then(|e| e.containing_shadow()) {
|
||||||
|
return shadow.elements_with_id(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collects elements with a given id under `root`, that pass `filter`.
|
/// Collects elements with a given id under `root`, that pass `filter`.
|
||||||
|
@ -280,8 +302,7 @@ fn collect_elements_with_id<E, Q, F>(
|
||||||
Q: SelectorQuery<E>,
|
Q: SelectorQuery<E>,
|
||||||
F: FnMut(E) -> bool,
|
F: FnMut(E) -> bool,
|
||||||
{
|
{
|
||||||
let doc = root.owner_doc();
|
let elements = match fast_connected_elements_with_id(root, id, quirks_mode) {
|
||||||
let elements = match fast_connected_elements_with_id(&doc, root, id, quirks_mode) {
|
|
||||||
Ok(elements) => elements,
|
Ok(elements) => elements,
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
|
let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
|
||||||
|
@ -297,7 +318,7 @@ fn collect_elements_with_id<E, Q, F>(
|
||||||
for element in elements {
|
for element in elements {
|
||||||
// If the element is not an actual descendant of the root, even though
|
// If the element is not an actual descendant of the root, even though
|
||||||
// it's connected, we don't really care about it.
|
// it's connected, we don't really care about it.
|
||||||
if !element_is_descendant_of(*element, root) {
|
if !connected_element_is_descendant_of(*element, root) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,9 +426,8 @@ where
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let doc = root.owner_doc();
|
let elements =
|
||||||
let elements = fast_connected_elements_with_id(&doc, root, id, quirks_mode)?;
|
fast_connected_elements_with_id(root, id, quirks_mode)?;
|
||||||
|
|
||||||
if elements.is_empty() {
|
if elements.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -432,7 +452,7 @@ where
|
||||||
//
|
//
|
||||||
// Give up on trying to optimize based on this id and
|
// Give up on trying to optimize based on this id and
|
||||||
// keep walking our selector.
|
// keep walking our selector.
|
||||||
if !element_is_descendant_of(*element, root) {
|
if !connected_element_is_descendant_of(*element, root) {
|
||||||
continue 'component_loop;
|
continue 'component_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,29 @@ use std::ptr;
|
||||||
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
||||||
use stylist::CascadeData;
|
use stylist::CascadeData;
|
||||||
|
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn elements_with_id<'a, 'le>(
|
||||||
|
array: *const structs::nsTArray<*mut RawGeckoElement>,
|
||||||
|
) -> &'a [GeckoElement<'le>] {
|
||||||
|
unsafe {
|
||||||
|
if array.is_null() {
|
||||||
|
return &[];
|
||||||
|
}
|
||||||
|
|
||||||
|
let elements: &[*mut RawGeckoElement] = &**array;
|
||||||
|
|
||||||
|
// NOTE(emilio): We rely on the in-memory representation of
|
||||||
|
// GeckoElement<'ld> and *mut RawGeckoElement being the same.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
unsafe fn static_assert() {
|
||||||
|
mem::transmute::<*mut RawGeckoElement, GeckoElement<'static>>(0xbadc0de as *mut _);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem::transmute(elements)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A simple wrapper over `nsIDocument`.
|
/// A simple wrapper over `nsIDocument`.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct GeckoDocument<'ld>(pub &'ld structs::nsIDocument);
|
pub struct GeckoDocument<'ld>(pub &'ld structs::nsIDocument);
|
||||||
|
@ -109,24 +132,14 @@ impl<'ld> TDocument for GeckoDocument<'ld> {
|
||||||
self.0.mCompatMode.into()
|
self.0.mCompatMode.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn elements_with_id(&self, id: &Atom) -> Result<&[GeckoElement<'ld>], ()> {
|
#[inline]
|
||||||
unsafe {
|
fn elements_with_id<'a>(&self, id: &Atom) -> Result<&'a [GeckoElement<'ld>], ()>
|
||||||
let array = bindings::Gecko_GetElementsWithId(self.0, id.as_ptr());
|
where
|
||||||
if array.is_null() {
|
Self: 'a,
|
||||||
return Ok(&[]);
|
{
|
||||||
}
|
Ok(elements_with_id(unsafe {
|
||||||
|
bindings::Gecko_Document_GetElementsWithId(self.0, id.as_ptr())
|
||||||
let elements: &[*mut RawGeckoElement] = &**array;
|
}))
|
||||||
|
|
||||||
// NOTE(emilio): We rely on the in-memory representation of
|
|
||||||
// GeckoElement<'ld> and *mut RawGeckoElement being the same.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
unsafe fn static_assert() {
|
|
||||||
mem::transmute::<*mut RawGeckoElement, GeckoElement<'static>>(0xbadc0de as *mut _);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(mem::transmute(elements))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +189,16 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> {
|
||||||
|
|
||||||
&author_styles.data
|
&author_styles.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn elements_with_id<'a>(&self, id: &Atom) -> Result<&'a [GeckoElement<'lr>], ()>
|
||||||
|
where
|
||||||
|
Self: 'a,
|
||||||
|
{
|
||||||
|
Ok(elements_with_id(unsafe {
|
||||||
|
bindings::Gecko_ShadowRoot_GetElementsWithId(self.0, id.as_ptr())
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A simple wrapper over a non-null Gecko node (`nsINode`) pointer.
|
/// A simple wrapper over a non-null Gecko node (`nsINode`) pointer.
|
||||||
|
@ -665,7 +688,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
fn non_xul_xbl_binding_parent_raw_content(&self) -> *mut nsIContent {
|
fn non_xul_xbl_binding_parent_raw_content(&self) -> *mut nsIContent {
|
||||||
debug_assert!(!self.is_xul_element());
|
debug_assert!(!self.is_xul_element());
|
||||||
self.extended_slots()
|
self.extended_slots()
|
||||||
.map_or(ptr::null_mut(), |slots| slots._base.mBindingParent)
|
.map_or(ptr::null_mut(), |slots| slots._base.mBindingParent.raw::<nsIContent>())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -13,13 +13,6 @@ impl<T> nsCOMPtr<T> {
|
||||||
pub fn raw<U>(&self) -> *mut T {
|
pub fn raw<U>(&self) -> *mut T {
|
||||||
self.mRawPtr
|
self.mRawPtr
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set this pointer from an addrefed raw pointer.
|
|
||||||
/// It leaks the old pointer.
|
|
||||||
#[inline]
|
|
||||||
pub unsafe fn set_raw_from_addrefed<U>(&mut self, ptr: *mut T) {
|
|
||||||
self.mRawPtr = ptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "gecko_debug"))]
|
#[cfg(not(feature = "gecko_debug"))]
|
||||||
|
@ -29,11 +22,4 @@ impl nsCOMPtr {
|
||||||
pub fn raw<T>(&self) -> *mut T {
|
pub fn raw<T>(&self) -> *mut T {
|
||||||
self._base.mRawPtr as *mut _
|
self._base.mRawPtr as *mut _
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set this pointer from an addrefed raw pointer.
|
|
||||||
/// It leaks the old pointer.
|
|
||||||
#[inline]
|
|
||||||
pub unsafe fn set_raw_from_addrefed<T>(&mut self, ptr: *mut T) {
|
|
||||||
self._base.mRawPtr = ptr as *mut _;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
|
|
||||||
use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
|
use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
|
||||||
use gecko_bindings::structs::{nscolor, StyleComplexColor};
|
use gecko_bindings::structs::{nscolor, StyleComplexColor};
|
||||||
|
use values::{Auto, Either};
|
||||||
use values::computed::Color as ComputedColor;
|
use values::computed::Color as ComputedColor;
|
||||||
use values::generics::ui::CaretColor;
|
use values::computed::ui::ColorOrAuto;
|
||||||
|
|
||||||
impl From<nscolor> for StyleComplexColor {
|
impl From<nscolor> for StyleComplexColor {
|
||||||
fn from(other: nscolor) -> Self {
|
fn from(other: nscolor) -> Self {
|
||||||
|
@ -59,27 +60,21 @@ impl From<StyleComplexColor> for ComputedColor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Color> From<CaretColor<Color>> for StyleComplexColor
|
impl From<ColorOrAuto> for StyleComplexColor {
|
||||||
where
|
fn from(other: ColorOrAuto) -> Self {
|
||||||
Color: Into<StyleComplexColor>,
|
|
||||||
{
|
|
||||||
fn from(other: CaretColor<Color>) -> Self {
|
|
||||||
match other {
|
match other {
|
||||||
CaretColor::Color(color) => color.into(),
|
Either::First(color) => color.into(),
|
||||||
CaretColor::Auto => StyleComplexColor::auto(),
|
Either::Second(_) => StyleComplexColor::auto(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Color> From<StyleComplexColor> for CaretColor<Color>
|
impl From<StyleComplexColor> for ColorOrAuto {
|
||||||
where
|
|
||||||
StyleComplexColor: Into<Color>,
|
|
||||||
{
|
|
||||||
fn from(other: StyleComplexColor) -> Self {
|
fn from(other: StyleComplexColor) -> Self {
|
||||||
if !other.mIsAuto {
|
if !other.mIsAuto {
|
||||||
CaretColor::Color(other.into())
|
Either::First(other.into())
|
||||||
} else {
|
} else {
|
||||||
CaretColor::Auto
|
Either::Second(Auto)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,10 +41,6 @@ bitflags! {
|
||||||
/// A flag used to mark styles which are a pseudo-element or under one.
|
/// A flag used to mark styles which are a pseudo-element or under one.
|
||||||
const IS_IN_PSEUDO_ELEMENT_SUBTREE = 1 << 4;
|
const IS_IN_PSEUDO_ELEMENT_SUBTREE = 1 << 4;
|
||||||
|
|
||||||
/// A flag used to mark styles which are in a display: none subtree, or
|
|
||||||
/// under one.
|
|
||||||
const IS_IN_DISPLAY_NONE_SUBTREE = 1 << 5;
|
|
||||||
|
|
||||||
/// Whether this style inherits the `display` property.
|
/// Whether this style inherits the `display` property.
|
||||||
///
|
///
|
||||||
/// This is important because it may affect our optimizations to avoid
|
/// This is important because it may affect our optimizations to avoid
|
||||||
|
@ -77,7 +73,6 @@ impl ComputedValueFlags {
|
||||||
ComputedValueFlags::IS_STYLE_IF_VISITED |
|
ComputedValueFlags::IS_STYLE_IF_VISITED |
|
||||||
ComputedValueFlags::IS_RELEVANT_LINK_VISITED |
|
ComputedValueFlags::IS_RELEVANT_LINK_VISITED |
|
||||||
ComputedValueFlags::CAN_BE_FRAGMENTED |
|
ComputedValueFlags::CAN_BE_FRAGMENTED |
|
||||||
ComputedValueFlags::IS_IN_DISPLAY_NONE_SUBTREE |
|
|
||||||
ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE |
|
ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE |
|
||||||
ComputedValueFlags::HAS_TEXT_DECORATION_LINES
|
ComputedValueFlags::HAS_TEXT_DECORATION_LINES
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,7 +164,7 @@ class Longhand(object):
|
||||||
allowed_in_keyframe_block=True, cast_type='u8',
|
allowed_in_keyframe_block=True, cast_type='u8',
|
||||||
logical=False, alias=None, extra_prefixes=None, boxed=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,
|
flags=None, allowed_in_page_rule=False, allow_quirks=False, ignored_when_colors_disabled=False,
|
||||||
vector=False, need_animatable=False, servo_restyle_damage="repaint"):
|
vector=False, servo_restyle_damage="repaint"):
|
||||||
self.name = name
|
self.name = name
|
||||||
if not spec:
|
if not spec:
|
||||||
raise TypeError("Spec should be specified for %s" % name)
|
raise TypeError("Spec should be specified for %s" % name)
|
||||||
|
|
|
@ -41,7 +41,6 @@ use gecko_bindings::structs;
|
||||||
use gecko_bindings::structs::nsCSSPropertyID;
|
use gecko_bindings::structs::nsCSSPropertyID;
|
||||||
use gecko_bindings::structs::mozilla::CSSPseudoElementType;
|
use gecko_bindings::structs::mozilla::CSSPseudoElementType;
|
||||||
use gecko_bindings::structs::mozilla::CSSPseudoElementType_InheritingAnonBox;
|
use gecko_bindings::structs::mozilla::CSSPseudoElementType_InheritingAnonBox;
|
||||||
use gecko_bindings::structs::root::NS_STYLE_CONTEXT_TYPE_SHIFT;
|
|
||||||
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
|
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
|
||||||
use gecko_bindings::sugar::refptr::RefPtr;
|
use gecko_bindings::sugar::refptr::RefPtr;
|
||||||
use gecko::values::convert_nscolor_to_rgba;
|
use gecko::values::convert_nscolor_to_rgba;
|
||||||
|
@ -137,12 +136,12 @@ impl ComputedValues {
|
||||||
PseudoElement::from_atom(&atom)
|
PseudoElement::from_atom(&atom)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn get_pseudo_type(&self) -> CSSPseudoElementType {
|
fn get_pseudo_type(&self) -> CSSPseudoElementType {
|
||||||
let bits = (self.0).mBits;
|
self.0.mPseudoType
|
||||||
let our_type = bits >> NS_STYLE_CONTEXT_TYPE_SHIFT;
|
|
||||||
unsafe { transmute(our_type as u8) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_anon_box(&self) -> bool {
|
pub fn is_anon_box(&self) -> bool {
|
||||||
let our_type = self.get_pseudo_type();
|
let our_type = self.get_pseudo_type();
|
||||||
return our_type == CSSPseudoElementType_InheritingAnonBox ||
|
return our_type == CSSPseudoElementType_InheritingAnonBox ||
|
||||||
|
@ -1436,6 +1435,7 @@ impl Clone for ${style_struct.gecko_struct_name} {
|
||||||
# Types used with predefined_type()-defined properties that we can auto-generate.
|
# Types used with predefined_type()-defined properties that we can auto-generate.
|
||||||
predefined_types = {
|
predefined_types = {
|
||||||
"Color": impl_color,
|
"Color": impl_color,
|
||||||
|
"ColorOrAuto": impl_color,
|
||||||
"GreaterThanOrEqualToOneNumber": impl_simple,
|
"GreaterThanOrEqualToOneNumber": impl_simple,
|
||||||
"Integer": impl_simple,
|
"Integer": impl_simple,
|
||||||
"length::LengthOrAuto": impl_style_coord,
|
"length::LengthOrAuto": impl_style_coord,
|
||||||
|
@ -2984,7 +2984,6 @@ fn static_assert() {
|
||||||
I::IntoIter: ExactSizeIterator + Clone
|
I::IntoIter: ExactSizeIterator + Clone
|
||||||
{
|
{
|
||||||
use properties::longhands::animation_${ident}::single_value::computed_value::T as Keyword;
|
use properties::longhands::animation_${ident}::single_value::computed_value::T as Keyword;
|
||||||
use gecko_bindings::structs;
|
|
||||||
|
|
||||||
let v = v.into_iter();
|
let v = v.into_iter();
|
||||||
|
|
||||||
|
@ -3248,7 +3247,7 @@ fn static_assert() {
|
||||||
|
|
||||||
pub fn clone_scroll_snap_coordinate(&self) -> longhands::scroll_snap_coordinate::computed_value::T {
|
pub fn clone_scroll_snap_coordinate(&self) -> longhands::scroll_snap_coordinate::computed_value::T {
|
||||||
let vec = self.gecko.mScrollSnapCoordinate.iter().map(|f| f.into()).collect();
|
let vec = self.gecko.mScrollSnapCoordinate.iter().map(|f| f.into()).collect();
|
||||||
longhands::scroll_snap_coordinate::computed_value::T(vec)
|
longhands::scroll_snap_coordinate::computed_value::List(vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
${impl_css_url('_moz_binding', 'mBinding')}
|
${impl_css_url('_moz_binding', 'mBinding')}
|
||||||
|
@ -3754,8 +3753,9 @@ fn static_assert() {
|
||||||
<% copy_simple_image_array_property(name, shorthand, layer_field_name, field_name) %>
|
<% copy_simple_image_array_property(name, shorthand, layer_field_name, field_name) %>
|
||||||
|
|
||||||
pub fn set_${ident}<I>(&mut self, v: I)
|
pub fn set_${ident}<I>(&mut self, v: I)
|
||||||
where I: IntoIterator<Item=longhands::${ident}::computed_value::single_value::T>,
|
where
|
||||||
I::IntoIter: ExactSizeIterator
|
I: IntoIterator<Item=longhands::${ident}::computed_value::single_value::T>,
|
||||||
|
I::IntoIter: ExactSizeIterator,
|
||||||
{
|
{
|
||||||
use properties::longhands::${ident}::single_value::computed_value::T as Keyword;
|
use properties::longhands::${ident}::single_value::computed_value::T as Keyword;
|
||||||
use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
|
use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
|
||||||
|
@ -3790,7 +3790,7 @@ fn static_assert() {
|
||||||
% endfor
|
% endfor
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
longhands::${ident}::computed_value::T (
|
longhands::${ident}::computed_value::List(
|
||||||
self.gecko.${layer_field_name}.mLayers.iter()
|
self.gecko.${layer_field_name}.mLayers.iter()
|
||||||
.take(self.gecko.${layer_field_name}.${field_name}Count as usize)
|
.take(self.gecko.${layer_field_name}.${field_name}Count as usize)
|
||||||
.map(|ref layer| {
|
.map(|ref layer| {
|
||||||
|
@ -3803,7 +3803,9 @@ fn static_assert() {
|
||||||
% endif
|
% endif
|
||||||
=> Keyword::${to_camel_case(value)},
|
=> Keyword::${to_camel_case(value)},
|
||||||
% endfor
|
% endfor
|
||||||
|
% if keyword.gecko_inexhaustive:
|
||||||
_ => panic!("Found unexpected value in style struct for ${ident} property"),
|
_ => panic!("Found unexpected value in style struct for ${ident} property"),
|
||||||
|
% endif
|
||||||
}
|
}
|
||||||
}).collect()
|
}).collect()
|
||||||
)
|
)
|
||||||
|
@ -3857,7 +3859,7 @@ fn static_assert() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
longhands::${shorthand}_repeat::computed_value::T (
|
longhands::${shorthand}_repeat::computed_value::List(
|
||||||
self.gecko.${image_layers_field}.mLayers.iter()
|
self.gecko.${image_layers_field}.mLayers.iter()
|
||||||
.take(self.gecko.${image_layers_field}.mRepeatCount as usize)
|
.take(self.gecko.${image_layers_field}.mRepeatCount as usize)
|
||||||
.map(|ref layer| {
|
.map(|ref layer| {
|
||||||
|
@ -3896,7 +3898,7 @@ fn static_assert() {
|
||||||
|
|
||||||
pub fn clone_${shorthand}_position_${orientation}(&self)
|
pub fn clone_${shorthand}_position_${orientation}(&self)
|
||||||
-> longhands::${shorthand}_position_${orientation}::computed_value::T {
|
-> longhands::${shorthand}_position_${orientation}::computed_value::T {
|
||||||
longhands::${shorthand}_position_${orientation}::computed_value::T(
|
longhands::${shorthand}_position_${orientation}::computed_value::List(
|
||||||
self.gecko.${image_layers_field}.mLayers.iter()
|
self.gecko.${image_layers_field}.mLayers.iter()
|
||||||
.take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize)
|
.take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize)
|
||||||
.map(|position| position.mPosition.m${orientation.upper()}Position.into())
|
.map(|position| position.mPosition.m${orientation.upper()}Position.into())
|
||||||
|
@ -3940,11 +3942,11 @@ fn static_assert() {
|
||||||
BackgroundSize::Explicit { width: explicit_width, height: explicit_height } => {
|
BackgroundSize::Explicit { width: explicit_width, height: explicit_height } => {
|
||||||
let mut w_type = nsStyleImageLayers_Size_DimensionType::eAuto;
|
let mut w_type = nsStyleImageLayers_Size_DimensionType::eAuto;
|
||||||
let mut h_type = nsStyleImageLayers_Size_DimensionType::eAuto;
|
let mut h_type = nsStyleImageLayers_Size_DimensionType::eAuto;
|
||||||
if let Some(w) = explicit_width.to_calc_value() {
|
if let Some(w) = explicit_width.0.to_calc_value() {
|
||||||
width = w;
|
width = w;
|
||||||
w_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage;
|
w_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage;
|
||||||
}
|
}
|
||||||
if let Some(h) = explicit_height.to_calc_value() {
|
if let Some(h) = explicit_height.0.to_calc_value() {
|
||||||
height = h;
|
height = h;
|
||||||
h_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage;
|
h_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage;
|
||||||
}
|
}
|
||||||
|
@ -3972,22 +3974,23 @@ fn static_assert() {
|
||||||
}
|
}
|
||||||
</%self:simple_image_array_property>
|
</%self:simple_image_array_property>
|
||||||
|
|
||||||
pub fn clone_${shorthand}_size(&self) -> longhands::background_size::computed_value::T {
|
pub fn clone_${shorthand}_size(&self) -> longhands::${shorthand}_size::computed_value::T {
|
||||||
use gecko_bindings::structs::nsStyleCoord_CalcValue as CalcValue;
|
use gecko_bindings::structs::nsStyleCoord_CalcValue as CalcValue;
|
||||||
use gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType as DimensionType;
|
use gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType as DimensionType;
|
||||||
use values::computed::LengthOrPercentageOrAuto;
|
use values::generics::NonNegative;
|
||||||
|
use values::computed::NonNegativeLengthOrPercentageOrAuto;
|
||||||
use values::generics::background::BackgroundSize;
|
use values::generics::background::BackgroundSize;
|
||||||
|
|
||||||
fn to_servo(value: CalcValue, ty: u8) -> LengthOrPercentageOrAuto {
|
fn to_servo(value: CalcValue, ty: u8) -> NonNegativeLengthOrPercentageOrAuto {
|
||||||
if ty == DimensionType::eAuto as u8 {
|
if ty == DimensionType::eAuto as u8 {
|
||||||
LengthOrPercentageOrAuto::Auto
|
NonNegativeLengthOrPercentageOrAuto::auto()
|
||||||
} else {
|
} else {
|
||||||
debug_assert_eq!(ty, DimensionType::eLengthPercentage as u8);
|
debug_assert_eq!(ty, DimensionType::eLengthPercentage as u8);
|
||||||
value.into()
|
NonNegative(value.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
longhands::background_size::computed_value::T(
|
longhands::${shorthand}_size::computed_value::List(
|
||||||
self.gecko.${image_layers_field}.mLayers.iter().map(|ref layer| {
|
self.gecko.${image_layers_field}.mLayers.iter().map(|ref layer| {
|
||||||
if DimensionType::eCover as u8 == layer.mSize.mWidthType {
|
if DimensionType::eCover as u8 == layer.mSize.mWidthType {
|
||||||
debug_assert_eq!(layer.mSize.mHeightType, DimensionType::eCover as u8);
|
debug_assert_eq!(layer.mSize.mHeightType, DimensionType::eCover as u8);
|
||||||
|
@ -4058,7 +4061,7 @@ fn static_assert() {
|
||||||
pub fn clone_${shorthand}_image(&self) -> longhands::${shorthand}_image::computed_value::T {
|
pub fn clone_${shorthand}_image(&self) -> longhands::${shorthand}_image::computed_value::T {
|
||||||
use values::None_;
|
use values::None_;
|
||||||
|
|
||||||
longhands::${shorthand}_image::computed_value::T(
|
longhands::${shorthand}_image::computed_value::List(
|
||||||
self.gecko.${image_layers_field}.mLayers.iter()
|
self.gecko.${image_layers_field}.mLayers.iter()
|
||||||
.take(self.gecko.${image_layers_field}.mImageCount as usize)
|
.take(self.gecko.${image_layers_field}.mImageCount as usize)
|
||||||
.map(|ref layer| {
|
.map(|ref layer| {
|
||||||
|
@ -4314,7 +4317,7 @@ fn static_assert() {
|
||||||
|
|
||||||
pub fn clone_box_shadow(&self) -> longhands::box_shadow::computed_value::T {
|
pub fn clone_box_shadow(&self) -> longhands::box_shadow::computed_value::T {
|
||||||
let buf = self.gecko.mBoxShadow.iter().map(|v| v.to_box_shadow()).collect();
|
let buf = self.gecko.mBoxShadow.iter().map(|v| v.to_box_shadow()).collect();
|
||||||
longhands::box_shadow::computed_value::T(buf)
|
longhands::box_shadow::computed_value::List(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_clip(&mut self, v: longhands::clip::computed_value::T) {
|
pub fn set_clip(&mut self, v: longhands::clip::computed_value::T) {
|
||||||
|
@ -4559,7 +4562,7 @@ fn static_assert() {
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
longhands::filter::computed_value::T(filters)
|
longhands::filter::computed_value::List(filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
@ -4680,7 +4683,7 @@ fn static_assert() {
|
||||||
|
|
||||||
pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T {
|
pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T {
|
||||||
let buf = self.gecko.mTextShadow.iter().map(|v| v.to_simple_shadow()).collect();
|
let buf = self.gecko.mTextShadow.iter().map(|v| v.to_simple_shadow()).collect();
|
||||||
longhands::text_shadow::computed_value::T(buf)
|
longhands::text_shadow::computed_value::List(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_line_height(&mut self, v: longhands::line_height::computed_value::T) {
|
pub fn set_line_height(&mut self, v: longhands::line_height::computed_value::T) {
|
||||||
|
@ -5303,7 +5306,7 @@ clip-path
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="InheritedUI"
|
<%self:impl_trait style_struct_name="InheritedUI"
|
||||||
skip_longhands="cursor caret-color">
|
skip_longhands="cursor">
|
||||||
pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) {
|
pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) {
|
||||||
use style_traits::cursor::CursorKind;
|
use style_traits::cursor::CursorKind;
|
||||||
|
|
||||||
|
@ -5449,8 +5452,6 @@ clip-path
|
||||||
|
|
||||||
longhands::cursor::computed_value::T { images, keyword }
|
longhands::cursor::computed_value::T { images, keyword }
|
||||||
}
|
}
|
||||||
|
|
||||||
<%call expr="impl_color('caret_color', 'mCaretColor')"></%call>
|
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="Column"
|
<%self:impl_trait style_struct_name="Column"
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
%>
|
%>
|
||||||
|
|
||||||
<%def name="predefined_type(name, type, initial_value, parse_method='parse',
|
<%def name="predefined_type(name, type, initial_value, parse_method='parse',
|
||||||
needs_context=True, vector=False, computed_type=None, initial_specified_value=None,
|
needs_context=True, vector=False,
|
||||||
|
computed_type=None, initial_specified_value=None,
|
||||||
allow_quirks=False, allow_empty=False, **kwargs)">
|
allow_quirks=False, allow_empty=False, **kwargs)">
|
||||||
<%def name="predefined_type_inner(name, type, initial_value, parse_method)">
|
<%def name="predefined_type_inner(name, type, initial_value, parse_method)">
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
|
@ -77,10 +78,12 @@
|
||||||
We assume that the default/initial value is an empty vector for these.
|
We assume that the default/initial value is an empty vector for these.
|
||||||
`initial_value` need not be defined for these.
|
`initial_value` need not be defined for these.
|
||||||
</%doc>
|
</%doc>
|
||||||
<%def name="vector_longhand(name, animation_value_type=None, allow_empty=False, separator='Comma',
|
<%def name="vector_longhand(name, animation_value_type=None,
|
||||||
need_animatable=False, **kwargs)">
|
vector_animation_type=None, allow_empty=False,
|
||||||
|
separator='Comma',
|
||||||
|
**kwargs)">
|
||||||
<%call expr="longhand(name, animation_value_type=animation_value_type, vector=True,
|
<%call expr="longhand(name, animation_value_type=animation_value_type, vector=True,
|
||||||
need_animatable=need_animatable, **kwargs)">
|
**kwargs)">
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
@ -115,36 +118,72 @@
|
||||||
% endif
|
% endif
|
||||||
use values::computed::ComputedVecIter;
|
use values::computed::ComputedVecIter;
|
||||||
|
|
||||||
/// The computed value, effectively a list of single values.
|
/// The generic type defining the value for this property.
|
||||||
|
///
|
||||||
|
/// Making this type generic allows the compiler to figure out the
|
||||||
|
/// animated value for us, instead of having to implement it
|
||||||
|
/// manually for every type we care about.
|
||||||
% if separator == "Comma":
|
% if separator == "Comma":
|
||||||
#[css(comma)]
|
#[css(comma)]
|
||||||
% endif
|
% endif
|
||||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
|
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToAnimatedValue,
|
||||||
% if need_animatable or animation_value_type == "ComputedValue":
|
ToCss)]
|
||||||
#[derive(Animate, ComputeSquaredDistance)]
|
pub struct List<T>(
|
||||||
% endif
|
|
||||||
pub struct T(
|
|
||||||
% if not allow_empty:
|
% if not allow_empty:
|
||||||
#[css(iterable)]
|
#[css(iterable)]
|
||||||
% else:
|
% else:
|
||||||
#[css(if_empty = "none", iterable)]
|
#[css(if_empty = "none", iterable)]
|
||||||
% endif
|
% endif
|
||||||
% if allow_empty and allow_empty != "NotInitial":
|
% if allow_empty and allow_empty != "NotInitial":
|
||||||
pub Vec<single_value::T>,
|
pub Vec<T>,
|
||||||
% else:
|
% else:
|
||||||
pub SmallVec<[single_value::T; 1]>,
|
pub SmallVec<[T; 1]>,
|
||||||
% endif
|
% endif
|
||||||
);
|
);
|
||||||
|
|
||||||
% if need_animatable or animation_value_type == "ComputedValue":
|
|
||||||
use values::animated::{ToAnimatedZero};
|
|
||||||
|
|
||||||
impl ToAnimatedZero for T {
|
/// The computed value, effectively a list of single values.
|
||||||
#[inline]
|
% if vector_animation_type:
|
||||||
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
|
% if not animation_value_type:
|
||||||
}
|
Sorry, this is stupid but needed for now.
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
|
use properties::animated_properties::ListAnimation;
|
||||||
|
use values::animated::{Animate, ToAnimatedValue, ToAnimatedZero, Procedure};
|
||||||
|
use values::distance::{SquaredDistance, ComputeSquaredDistance};
|
||||||
|
|
||||||
|
// FIXME(emilio): For some reason rust thinks that this alias is
|
||||||
|
// unused, even though it's clearly used below?
|
||||||
|
#[allow(unused)]
|
||||||
|
type AnimatedList = <List<single_value::T> as ToAnimatedValue>::AnimatedValue;
|
||||||
|
|
||||||
|
impl ToAnimatedZero for AnimatedList {
|
||||||
|
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Animate for AnimatedList {
|
||||||
|
fn animate(
|
||||||
|
&self,
|
||||||
|
other: &Self,
|
||||||
|
procedure: Procedure,
|
||||||
|
) -> Result<Self, ()> {
|
||||||
|
Ok(List(
|
||||||
|
self.0.animate_${vector_animation_type}(&other.0, procedure)?
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ComputeSquaredDistance for AnimatedList {
|
||||||
|
fn compute_squared_distance(
|
||||||
|
&self,
|
||||||
|
other: &Self,
|
||||||
|
) -> Result<SquaredDistance, ()> {
|
||||||
|
self.0.squared_distance_${vector_animation_type}(&other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
% endif
|
||||||
|
|
||||||
|
pub type T = List<single_value::T>;
|
||||||
|
|
||||||
pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>;
|
pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>;
|
||||||
|
|
||||||
impl IntoIterator for T {
|
impl IntoIterator for T {
|
||||||
|
@ -176,16 +215,18 @@
|
||||||
|
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
pub fn get_initial_value() -> computed_value::T {
|
||||||
% if allow_empty and allow_empty != "NotInitial":
|
% if allow_empty and allow_empty != "NotInitial":
|
||||||
computed_value::T(vec![])
|
computed_value::List(vec![])
|
||||||
% else:
|
% else:
|
||||||
let mut v = SmallVec::new();
|
let mut v = SmallVec::new();
|
||||||
v.push(single_value::get_initial_value());
|
v.push(single_value::get_initial_value());
|
||||||
computed_value::T(v)
|
computed_value::List(v)
|
||||||
% endif
|
% endif
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
|
pub fn parse<'i, 't>(
|
||||||
-> Result<SpecifiedValue, ParseError<'i>> {
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<SpecifiedValue, ParseError<'i>> {
|
||||||
use style_traits::Separator;
|
use style_traits::Separator;
|
||||||
|
|
||||||
% if allow_empty:
|
% if allow_empty:
|
||||||
|
@ -202,8 +243,10 @@
|
||||||
pub use self::single_value::SpecifiedValue as SingleSpecifiedValue;
|
pub use self::single_value::SpecifiedValue as SingleSpecifiedValue;
|
||||||
|
|
||||||
impl SpecifiedValue {
|
impl SpecifiedValue {
|
||||||
pub fn compute_iter<'a, 'cx, 'cx_a>(&'a self, context: &'cx Context<'cx_a>)
|
pub fn compute_iter<'a, 'cx, 'cx_a>(
|
||||||
-> computed_value::Iter<'a, 'cx, 'cx_a> {
|
&'a self,
|
||||||
|
context: &'cx Context<'cx_a>,
|
||||||
|
) -> computed_value::Iter<'a, 'cx, 'cx_a> {
|
||||||
computed_value::Iter::new(context, &self.0)
|
computed_value::Iter::new(context, &self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,7 +256,7 @@
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||||
computed_value::T(self.compute_iter(context).collect())
|
computed_value::List(self.compute_iter(context).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -29,11 +29,10 @@ use std::mem::{self, ManuallyDrop};
|
||||||
#[cfg(feature = "gecko")] use hash::FnvHashMap;
|
#[cfg(feature = "gecko")] use hash::FnvHashMap;
|
||||||
use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo};
|
use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo};
|
||||||
use super::ComputedValues;
|
use super::ComputedValues;
|
||||||
use values::{CSSFloat, CustomIdent, Either};
|
use values::{CSSFloat, CustomIdent};
|
||||||
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
|
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
|
||||||
use values::animated::color::RGBA as AnimatedRGBA;
|
use values::animated::color::RGBA as AnimatedRGBA;
|
||||||
use values::animated::effects::Filter as AnimatedFilter;
|
use values::animated::effects::Filter as AnimatedFilter;
|
||||||
use values::animated::effects::FilterList as AnimatedFilterList;
|
|
||||||
use values::computed::{Angle, CalcLengthOrPercentage};
|
use values::computed::{Angle, CalcLengthOrPercentage};
|
||||||
use values::computed::{ClipRect, Context};
|
use values::computed::{ClipRect, Context};
|
||||||
use values::computed::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
|
use values::computed::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
|
@ -53,13 +52,10 @@ use values::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||||
use values::generics::font::{FontSettings as GenericFontSettings, FontTag, VariationValue};
|
use values::generics::font::{FontSettings as GenericFontSettings, FontTag, VariationValue};
|
||||||
use values::computed::font::FontVariationSettings;
|
use values::computed::font::FontVariationSettings;
|
||||||
use values::generics::effects::Filter;
|
use values::generics::effects::Filter;
|
||||||
use values::generics::position as generic_position;
|
|
||||||
use values::generics::svg::{SVGLength, SvgLengthOrPercentageOrNumber, SVGPaint};
|
use values::generics::svg::{SVGLength, SvgLengthOrPercentageOrNumber, SVGPaint};
|
||||||
use values::generics::svg::{SVGPaintKind, SVGStrokeDashArray, SVGOpacity};
|
use values::generics::svg::{SVGPaintKind, SVGStrokeDashArray, SVGOpacity};
|
||||||
use void::{self, Void};
|
use void::{self, Void};
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-transitions/#animtype-repeatable-list>
|
|
||||||
pub trait RepeatableListAnimatable: Animate {}
|
|
||||||
|
|
||||||
/// Returns true if this nsCSSPropertyID is one of the animatable properties.
|
/// Returns true if this nsCSSPropertyID is one of the animatable properties.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
@ -755,18 +751,45 @@ impl ToAnimatedZero for AnimationValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RepeatableListAnimatable for LengthOrPercentage {}
|
/// A trait to abstract away the different kind of animations over a list that
|
||||||
impl RepeatableListAnimatable for Either<f32, LengthOrPercentage> {}
|
/// there may be.
|
||||||
impl RepeatableListAnimatable for Either<NonNegativeNumber, NonNegativeLengthOrPercentage> {}
|
pub trait ListAnimation<T> : Sized {
|
||||||
impl RepeatableListAnimatable for SvgLengthOrPercentageOrNumber<LengthOrPercentage, Number> {}
|
/// <https://drafts.csswg.org/css-transitions/#animtype-repeatable-list>
|
||||||
|
fn animate_repeatable_list(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>
|
||||||
|
where
|
||||||
|
T: Animate;
|
||||||
|
|
||||||
macro_rules! repeated_vec_impl {
|
/// <https://drafts.csswg.org/css-transitions/#animtype-repeatable-list>
|
||||||
($($ty:ty),*) => {
|
fn squared_distance_repeatable_list(&self, other: &Self) -> Result<SquaredDistance, ()>
|
||||||
$(impl<T> Animate for $ty
|
where
|
||||||
where
|
T: ComputeSquaredDistance;
|
||||||
T: RepeatableListAnimatable,
|
|
||||||
{
|
/// This is the animation used for some of the types like shadows and
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
/// filters, where the interpolation happens with the zero value if one of
|
||||||
|
/// the sides is not present.
|
||||||
|
fn animate_with_zero(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>
|
||||||
|
where
|
||||||
|
T: Animate + Clone + ToAnimatedZero;
|
||||||
|
|
||||||
|
/// This is the animation used for some of the types like shadows and
|
||||||
|
/// filters, where the interpolation happens with the zero value if one of
|
||||||
|
/// the sides is not present.
|
||||||
|
fn squared_distance_with_zero(&self, other: &Self) -> Result<SquaredDistance, ()>
|
||||||
|
where
|
||||||
|
T: ToAnimatedZero + ComputeSquaredDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! animated_list_impl {
|
||||||
|
(<$t:ident> for $ty:ty) => {
|
||||||
|
impl<$t> ListAnimation<$t> for $ty {
|
||||||
|
fn animate_repeatable_list(
|
||||||
|
&self,
|
||||||
|
other: &Self,
|
||||||
|
procedure: Procedure,
|
||||||
|
) -> Result<Self, ()>
|
||||||
|
where
|
||||||
|
T: Animate,
|
||||||
|
{
|
||||||
// If the length of either list is zero, the least common multiple is undefined.
|
// If the length of either list is zero, the least common multiple is undefined.
|
||||||
if self.is_empty() || other.is_empty() {
|
if self.is_empty() || other.is_empty() {
|
||||||
return Err(());
|
return Err(());
|
||||||
|
@ -777,14 +800,14 @@ macro_rules! repeated_vec_impl {
|
||||||
this.animate(other, procedure)
|
this.animate(other, procedure)
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> ComputeSquaredDistance for $ty
|
fn squared_distance_repeatable_list(
|
||||||
where
|
&self,
|
||||||
T: ComputeSquaredDistance + RepeatableListAnimatable,
|
other: &Self,
|
||||||
{
|
) -> Result<SquaredDistance, ()>
|
||||||
#[inline]
|
where
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
T: ComputeSquaredDistance,
|
||||||
|
{
|
||||||
if self.is_empty() || other.is_empty() {
|
if self.is_empty() || other.is_empty() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
@ -794,11 +817,59 @@ macro_rules! repeated_vec_impl {
|
||||||
this.compute_squared_distance(other)
|
this.compute_squared_distance(other)
|
||||||
}).sum()
|
}).sum()
|
||||||
}
|
}
|
||||||
})*
|
|
||||||
};
|
fn animate_with_zero(
|
||||||
|
&self,
|
||||||
|
other: &Self,
|
||||||
|
procedure: Procedure,
|
||||||
|
) -> Result<Self, ()>
|
||||||
|
where
|
||||||
|
T: Animate + Clone + ToAnimatedZero
|
||||||
|
{
|
||||||
|
if procedure == Procedure::Add {
|
||||||
|
return Ok(
|
||||||
|
self.iter().chain(other.iter()).cloned().collect()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.iter().zip_longest(other.iter()).map(|it| {
|
||||||
|
match it {
|
||||||
|
EitherOrBoth::Both(this, other) => {
|
||||||
|
this.animate(other, procedure)
|
||||||
|
},
|
||||||
|
EitherOrBoth::Left(this) => {
|
||||||
|
this.animate(&this.to_animated_zero()?, procedure)
|
||||||
|
},
|
||||||
|
EitherOrBoth::Right(other) => {
|
||||||
|
other.to_animated_zero()?.animate(other, procedure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn squared_distance_with_zero(
|
||||||
|
&self,
|
||||||
|
other: &Self,
|
||||||
|
) -> Result<SquaredDistance, ()>
|
||||||
|
where
|
||||||
|
T: ToAnimatedZero + ComputeSquaredDistance
|
||||||
|
{
|
||||||
|
self.iter().zip_longest(other.iter()).map(|it| {
|
||||||
|
match it {
|
||||||
|
EitherOrBoth::Both(this, other) => {
|
||||||
|
this.compute_squared_distance(other)
|
||||||
|
},
|
||||||
|
EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => {
|
||||||
|
list.to_animated_zero()?.compute_squared_distance(list)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}).sum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repeated_vec_impl!(SmallVec<[T; 1]>, Vec<T>);
|
animated_list_impl!(<T> for SmallVec<[T; 1]>);
|
||||||
|
animated_list_impl!(<T> for Vec<T>);
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-transitions/#animtype-visibility>
|
/// <https://drafts.csswg.org/css-transitions/#animtype-visibility>
|
||||||
impl Animate for Visibility {
|
impl Animate for Visibility {
|
||||||
|
@ -1027,9 +1098,6 @@ impl<'a> Iterator for FontSettingTagIter<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, V> RepeatableListAnimatable for generic_position::Position<H, V>
|
|
||||||
where H: RepeatableListAnimatable, V: RepeatableListAnimatable {}
|
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-transitions/#animtype-rect>
|
/// <https://drafts.csswg.org/css-transitions/#animtype-rect>
|
||||||
impl Animate for ClipRect {
|
impl Animate for ClipRect {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1221,25 +1289,21 @@ impl Animate for ComputedTransformOperation {
|
||||||
) => {
|
) => {
|
||||||
Ok(TransformOperation::Scale(
|
Ok(TransformOperation::Scale(
|
||||||
animate_multiplicative_factor(*fx, *tx, procedure)?,
|
animate_multiplicative_factor(*fx, *tx, procedure)?,
|
||||||
Some(animate_multiplicative_factor(fy.unwrap_or(*fx), ty.unwrap_or(*tx), procedure)?),
|
Some(animate_multiplicative_factor(
|
||||||
|
fy.unwrap_or(*fx),
|
||||||
|
ty.unwrap_or(*tx),
|
||||||
|
procedure
|
||||||
|
)?),
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
(
|
(
|
||||||
&TransformOperation::Rotate3D(fx, fy, fz, fa),
|
&TransformOperation::Rotate3D(fx, fy, fz, fa),
|
||||||
&TransformOperation::Rotate3D(tx, ty, tz, ta),
|
&TransformOperation::Rotate3D(tx, ty, tz, ta),
|
||||||
) => {
|
) => {
|
||||||
let (fx, fy, fz, fa) = transform::get_normalized_vector_and_angle(fx, fy, fz, fa);
|
let animated = Rotate::Rotate3D(fx, fy, fz, fa)
|
||||||
let (tx, ty, tz, ta) = transform::get_normalized_vector_and_angle(tx, ty, tz, ta);
|
.animate(&Rotate::Rotate3D(tx, ty, tz, ta), procedure)?;
|
||||||
if (fx, fy, fz) == (tx, ty, tz) {
|
let (fx, fy, fz, fa) = ComputedRotate::resolve(&animated);
|
||||||
let ia = fa.animate(&ta, procedure)?;
|
Ok(TransformOperation::Rotate3D(fx, fy, fz, fa))
|
||||||
Ok(TransformOperation::Rotate3D(fx, fy, fz, ia))
|
|
||||||
} else {
|
|
||||||
let matrix_f = rotate_to_matrix(fx, fy, fz, fa);
|
|
||||||
let matrix_t = rotate_to_matrix(tx, ty, tz, ta);
|
|
||||||
Ok(TransformOperation::Matrix3D(
|
|
||||||
matrix_f.animate(&matrix_t, procedure)?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
(
|
(
|
||||||
&TransformOperation::RotateX(fa),
|
&TransformOperation::RotateX(fa),
|
||||||
|
@ -1303,6 +1367,9 @@ impl Animate for ComputedTransformOperation {
|
||||||
_ if self.is_scale() && other.is_scale() => {
|
_ if self.is_scale() && other.is_scale() => {
|
||||||
self.to_scale_3d().animate(&other.to_scale_3d(), procedure)
|
self.to_scale_3d().animate(&other.to_scale_3d(), procedure)
|
||||||
}
|
}
|
||||||
|
_ if self.is_rotate() && other.is_rotate() => {
|
||||||
|
self.to_rotate_3d().animate(&other.to_rotate_3d(), procedure)
|
||||||
|
}
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1335,40 +1402,12 @@ fn is_matched_operation(first: &ComputedTransformOperation, second: &ComputedTra
|
||||||
// we animate scale and translate operations against each other
|
// we animate scale and translate operations against each other
|
||||||
(a, b) if a.is_translate() && b.is_translate() => true,
|
(a, b) if a.is_translate() && b.is_translate() => true,
|
||||||
(a, b) if a.is_scale() && b.is_scale() => true,
|
(a, b) if a.is_scale() && b.is_scale() => true,
|
||||||
|
(a, b) if a.is_rotate() && b.is_rotate() => true,
|
||||||
// InterpolateMatrix and AccumulateMatrix are for mismatched transform.
|
// InterpolateMatrix and AccumulateMatrix are for mismatched transform.
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://www.w3.org/TR/css-transforms-1/#Rotate3dDefined>
|
|
||||||
fn rotate_to_matrix(x: f32, y: f32, z: f32, a: Angle) -> Matrix3D {
|
|
||||||
let half_rad = a.radians() / 2.0;
|
|
||||||
let sc = (half_rad).sin() * (half_rad).cos();
|
|
||||||
let sq = (half_rad).sin().powi(2);
|
|
||||||
|
|
||||||
Matrix3D {
|
|
||||||
m11: 1.0 - 2.0 * (y * y + z * z) * sq,
|
|
||||||
m12: 2.0 * (x * y * sq + z * sc),
|
|
||||||
m13: 2.0 * (x * z * sq - y * sc),
|
|
||||||
m14: 0.0,
|
|
||||||
|
|
||||||
m21: 2.0 * (x * y * sq - z * sc),
|
|
||||||
m22: 1.0 - 2.0 * (x * x + z * z) * sq,
|
|
||||||
m23: 2.0 * (y * z * sq + x * sc),
|
|
||||||
m24: 0.0,
|
|
||||||
|
|
||||||
m31: 2.0 * (x * z * sq + y * sc),
|
|
||||||
m32: 2.0 * (y * z * sq - x * sc),
|
|
||||||
m33: 1.0 - 2.0 * (x * x + y * y) * sq,
|
|
||||||
m34: 0.0,
|
|
||||||
|
|
||||||
m41: 0.0,
|
|
||||||
m42: 0.0,
|
|
||||||
m43: 0.0,
|
|
||||||
m44: 1.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A 2d matrix for interpolation.
|
/// A 2d matrix for interpolation.
|
||||||
#[derive(Clone, ComputeSquaredDistance, Copy, Debug)]
|
#[derive(Clone, ComputeSquaredDistance, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
||||||
|
@ -1464,10 +1503,10 @@ impl Animate for MatrixDecomposed2D {
|
||||||
let matrix = self.matrix.animate(&other.matrix, procedure)?;
|
let matrix = self.matrix.animate(&other.matrix, procedure)?;
|
||||||
|
|
||||||
Ok(MatrixDecomposed2D {
|
Ok(MatrixDecomposed2D {
|
||||||
translate: translate,
|
translate,
|
||||||
scale: scale,
|
scale,
|
||||||
angle: angle,
|
angle,
|
||||||
matrix: matrix,
|
matrix,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1781,12 +1820,16 @@ impl Animate for Quaternion {
|
||||||
use std::f64;
|
use std::f64;
|
||||||
|
|
||||||
let (this_weight, other_weight) = procedure.weights();
|
let (this_weight, other_weight) = procedure.weights();
|
||||||
debug_assert!((this_weight + other_weight - 1.0f64).abs() <= f64::EPSILON ||
|
debug_assert!(
|
||||||
other_weight == 1.0f64 || other_weight == 0.0f64,
|
(this_weight + other_weight - 1.0f64).abs() <= f64::EPSILON ||
|
||||||
"animate should only be used for interpolating or accumulating transforms");
|
other_weight == 1.0f64 || other_weight == 0.0f64,
|
||||||
|
"animate should only be used for interpolating or accumulating transforms"
|
||||||
|
);
|
||||||
|
|
||||||
// We take a specialized code path for accumulation (where other_weight is 1)
|
// We take a specialized code path for accumulation (where other_weight
|
||||||
if other_weight == 1.0 {
|
// is 1).
|
||||||
|
if let Procedure::Accumulate { .. } = procedure {
|
||||||
|
debug_assert_eq!(other_weight, 1.0);
|
||||||
if this_weight == 0.0 {
|
if this_weight == 0.0 {
|
||||||
return Ok(*other);
|
return Ok(*other);
|
||||||
}
|
}
|
||||||
|
@ -1817,32 +1860,39 @@ impl Animate for Quaternion {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut product = self.0 * other.0 +
|
// Straight from gfxQuaternion::Slerp.
|
||||||
self.1 * other.1 +
|
//
|
||||||
self.2 * other.2 +
|
// Dot product, clamped between -1 and 1.
|
||||||
self.3 * other.3;
|
let dot =
|
||||||
|
(self.0 * other.0 +
|
||||||
|
self.1 * other.1 +
|
||||||
|
self.2 * other.2 +
|
||||||
|
self.3 * other.3)
|
||||||
|
.min(1.0).max(-1.0);
|
||||||
|
|
||||||
// Clamp product to -1.0 <= product <= 1.0
|
if dot == 1.0 {
|
||||||
product = product.min(1.0);
|
|
||||||
product = product.max(-1.0);
|
|
||||||
|
|
||||||
if product == 1.0 {
|
|
||||||
return Ok(*self);
|
return Ok(*self);
|
||||||
}
|
}
|
||||||
|
|
||||||
let theta = product.acos();
|
let theta = dot.acos();
|
||||||
let w = (other_weight * theta).sin() * 1.0 / (1.0 - product * product).sqrt();
|
let rsintheta = 1.0 / (1.0 - dot * dot).sqrt();
|
||||||
|
|
||||||
let mut a = *self;
|
let right_weight = (other_weight * theta).sin() * rsintheta;
|
||||||
let mut b = *other;
|
let left_weight = (other_weight * theta).cos() - dot * right_weight;
|
||||||
let mut result = Quaternion(0., 0., 0., 0.,);
|
|
||||||
|
let mut left = *self;
|
||||||
|
let mut right = *other;
|
||||||
% for i in range(4):
|
% for i in range(4):
|
||||||
a.${i} *= (other_weight * theta).cos() - product * w;
|
left.${i} *= left_weight;
|
||||||
b.${i} *= w;
|
right.${i} *= right_weight;
|
||||||
result.${i} = a.${i} + b.${i};
|
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
Ok(result)
|
Ok(Quaternion(
|
||||||
|
left.0 + right.0,
|
||||||
|
left.1 + right.1,
|
||||||
|
left.2 + right.2,
|
||||||
|
left.3 + right.3,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1858,7 +1908,8 @@ impl ComputeSquaredDistance for Quaternion {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decompose a 3D matrix.
|
/// Decompose a 3D matrix.
|
||||||
/// <https://drafts.csswg.org/css-transforms/#decomposing-a-3d-matrix>
|
/// https://drafts.csswg.org/css-transforms-2/#decomposing-a-3d-matrix
|
||||||
|
/// http://www.realtimerendering.com/resources/GraphicsGems/gemsii/unmatrix.c
|
||||||
fn decompose_3d_matrix(mut matrix: Matrix3D) -> Result<MatrixDecomposed3D, ()> {
|
fn decompose_3d_matrix(mut matrix: Matrix3D) -> Result<MatrixDecomposed3D, ()> {
|
||||||
// Normalize the matrix.
|
// Normalize the matrix.
|
||||||
if matrix.m44 == 0.0 {
|
if matrix.m44 == 0.0 {
|
||||||
|
@ -1866,6 +1917,8 @@ fn decompose_3d_matrix(mut matrix: Matrix3D) -> Result<MatrixDecomposed3D, ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let scaling_factor = matrix.m44;
|
let scaling_factor = matrix.m44;
|
||||||
|
|
||||||
|
// Normalize the matrix.
|
||||||
% for i in range(1, 5):
|
% for i in range(1, 5):
|
||||||
% for j in range(1, 5):
|
% for j in range(1, 5):
|
||||||
matrix.m${i}${j} /= scaling_factor;
|
matrix.m${i}${j} /= scaling_factor;
|
||||||
|
@ -1876,9 +1929,9 @@ fn decompose_3d_matrix(mut matrix: Matrix3D) -> Result<MatrixDecomposed3D, ()> {
|
||||||
// an easy way to test for singularity of the upper 3x3 component.
|
// an easy way to test for singularity of the upper 3x3 component.
|
||||||
let mut perspective_matrix = matrix;
|
let mut perspective_matrix = matrix;
|
||||||
|
|
||||||
% for i in range(1, 4):
|
perspective_matrix.m14 = 0.0;
|
||||||
perspective_matrix.m${i}4 = 0.0;
|
perspective_matrix.m24 = 0.0;
|
||||||
% endfor
|
perspective_matrix.m34 = 0.0;
|
||||||
perspective_matrix.m44 = 1.0;
|
perspective_matrix.m44 = 1.0;
|
||||||
|
|
||||||
if perspective_matrix.determinant() == 0.0 {
|
if perspective_matrix.determinant() == 0.0 {
|
||||||
|
@ -1894,37 +1947,18 @@ fn decompose_3d_matrix(mut matrix: Matrix3D) -> Result<MatrixDecomposed3D, ()> {
|
||||||
matrix.m44
|
matrix.m44
|
||||||
];
|
];
|
||||||
|
|
||||||
perspective_matrix = perspective_matrix.inverse().unwrap();
|
perspective_matrix = perspective_matrix.inverse().unwrap().transpose();
|
||||||
|
let perspective = perspective_matrix.pre_mul_point4(&right_hand_side);
|
||||||
// Transpose perspective_matrix
|
// NOTE(emilio): Even though the reference algorithm clears the
|
||||||
perspective_matrix = Matrix3D {
|
// fourth column here (matrix.m14..matrix.m44), they're not used below
|
||||||
% for i in range(1, 5):
|
// so it's not really needed.
|
||||||
% for j in range(1, 5):
|
Perspective(perspective[0], perspective[1], perspective[2], perspective[3])
|
||||||
m${i}${j}: perspective_matrix.m${j}${i},
|
|
||||||
% endfor
|
|
||||||
% endfor
|
|
||||||
};
|
|
||||||
|
|
||||||
// Multiply right_hand_side with perspective_matrix
|
|
||||||
let mut tmp: [f32; 4] = [0.0; 4];
|
|
||||||
% for i in range(1, 5):
|
|
||||||
tmp[${i - 1}] = (right_hand_side[0] * perspective_matrix.m1${i}) +
|
|
||||||
(right_hand_side[1] * perspective_matrix.m2${i}) +
|
|
||||||
(right_hand_side[2] * perspective_matrix.m3${i}) +
|
|
||||||
(right_hand_side[3] * perspective_matrix.m4${i});
|
|
||||||
% endfor
|
|
||||||
|
|
||||||
Perspective(tmp[0], tmp[1], tmp[2], tmp[3])
|
|
||||||
} else {
|
} else {
|
||||||
Perspective(0.0, 0.0, 0.0, 1.0)
|
Perspective(0.0, 0.0, 0.0, 1.0)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Next take care of translation
|
// Next take care of translation (easy).
|
||||||
let translate = Translate3D (
|
let translate = Translate3D(matrix.m41, matrix.m42, matrix.m43);
|
||||||
matrix.m41,
|
|
||||||
matrix.m42,
|
|
||||||
matrix.m43
|
|
||||||
);
|
|
||||||
|
|
||||||
// Now get scale and shear. 'row' is a 3 element array of 3 component vectors
|
// Now get scale and shear. 'row' is a 3 element array of 3 component vectors
|
||||||
let mut row: [[f32; 3]; 3] = [[0.0; 3]; 3];
|
let mut row: [[f32; 3]; 3] = [[0.0; 3]; 3];
|
||||||
|
@ -1965,8 +1999,7 @@ fn decompose_3d_matrix(mut matrix: Matrix3D) -> Result<MatrixDecomposed3D, ()> {
|
||||||
// At this point, the matrix (in rows) is orthonormal.
|
// At this point, the matrix (in rows) is orthonormal.
|
||||||
// Check for a coordinate system flip. If the determinant
|
// Check for a coordinate system flip. If the determinant
|
||||||
// is -1, then negate the matrix and the scaling factors.
|
// is -1, then negate the matrix and the scaling factors.
|
||||||
let pdum3 = cross(row[1], row[2]);
|
if dot(row[0], cross(row[1], row[2])) < 0.0 {
|
||||||
if dot(row[0], pdum3) < 0.0 {
|
|
||||||
% for i in range(3):
|
% for i in range(3):
|
||||||
scale.${i} *= -1.0;
|
scale.${i} *= -1.0;
|
||||||
row[${i}][0] *= -1.0;
|
row[${i}][0] *= -1.0;
|
||||||
|
@ -1975,8 +2008,8 @@ fn decompose_3d_matrix(mut matrix: Matrix3D) -> Result<MatrixDecomposed3D, ()> {
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, get the rotations out
|
// Now, get the rotations out.
|
||||||
let mut quaternion = Quaternion (
|
let mut quaternion = Quaternion(
|
||||||
0.5 * ((1.0 + row[0][0] - row[1][1] - row[2][2]).max(0.0) as f64).sqrt(),
|
0.5 * ((1.0 + row[0][0] - row[1][1] - row[2][2]).max(0.0) as f64).sqrt(),
|
||||||
0.5 * ((1.0 - row[0][0] + row[1][1] - row[2][2]).max(0.0) as f64).sqrt(),
|
0.5 * ((1.0 - row[0][0] + row[1][1] - row[2][2]).max(0.0) as f64).sqrt(),
|
||||||
0.5 * ((1.0 - row[0][0] - row[1][1] + row[2][2]).max(0.0) as f64).sqrt(),
|
0.5 * ((1.0 - row[0][0] - row[1][1] + row[2][2]).max(0.0) as f64).sqrt(),
|
||||||
|
@ -1994,11 +2027,11 @@ fn decompose_3d_matrix(mut matrix: Matrix3D) -> Result<MatrixDecomposed3D, ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(MatrixDecomposed3D {
|
Ok(MatrixDecomposed3D {
|
||||||
translate: translate,
|
translate,
|
||||||
scale: scale,
|
scale,
|
||||||
skew: skew,
|
skew,
|
||||||
perspective: perspective,
|
perspective,
|
||||||
quaternion: quaternion
|
quaternion,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2121,57 +2154,61 @@ impl From<MatrixDecomposed3D> for Matrix3D {
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
// Apply translation
|
// Apply translation
|
||||||
% for i in range(1, 4):
|
% for i in range(1, 5):
|
||||||
% for j in range(1, 4):
|
% for j in range(1, 4):
|
||||||
matrix.m4${i} += decomposed.translate.${j - 1} * matrix.m${j}${i};
|
matrix.m4${i} += decomposed.translate.${j - 1} * matrix.m${j}${i};
|
||||||
% endfor
|
% endfor
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
// Apply rotation
|
// Apply rotation
|
||||||
let x = decomposed.quaternion.0;
|
{
|
||||||
let y = decomposed.quaternion.1;
|
let x = decomposed.quaternion.0;
|
||||||
let z = decomposed.quaternion.2;
|
let y = decomposed.quaternion.1;
|
||||||
let w = decomposed.quaternion.3;
|
let z = decomposed.quaternion.2;
|
||||||
|
let w = decomposed.quaternion.3;
|
||||||
|
|
||||||
// Construct a composite rotation matrix from the quaternion values
|
// Construct a composite rotation matrix from the quaternion values
|
||||||
// rotationMatrix is a identity 4x4 matrix initially
|
// rotationMatrix is a identity 4x4 matrix initially
|
||||||
let mut rotation_matrix = Matrix3D::identity();
|
let mut rotation_matrix = Matrix3D::identity();
|
||||||
rotation_matrix.m11 = 1.0 - 2.0 * (y * y + z * z) as f32;
|
rotation_matrix.m11 = 1.0 - 2.0 * (y * y + z * z) as f32;
|
||||||
rotation_matrix.m12 = 2.0 * (x * y + z * w) as f32;
|
rotation_matrix.m12 = 2.0 * (x * y + z * w) as f32;
|
||||||
rotation_matrix.m13 = 2.0 * (x * z - y * w) as f32;
|
rotation_matrix.m13 = 2.0 * (x * z - y * w) as f32;
|
||||||
rotation_matrix.m21 = 2.0 * (x * y - z * w) as f32;
|
rotation_matrix.m21 = 2.0 * (x * y - z * w) as f32;
|
||||||
rotation_matrix.m22 = 1.0 - 2.0 * (x * x + z * z) as f32;
|
rotation_matrix.m22 = 1.0 - 2.0 * (x * x + z * z) as f32;
|
||||||
rotation_matrix.m23 = 2.0 * (y * z + x * w) as f32;
|
rotation_matrix.m23 = 2.0 * (y * z + x * w) as f32;
|
||||||
rotation_matrix.m31 = 2.0 * (x * z + y * w) as f32;
|
rotation_matrix.m31 = 2.0 * (x * z + y * w) as f32;
|
||||||
rotation_matrix.m32 = 2.0 * (y * z - x * w) as f32;
|
rotation_matrix.m32 = 2.0 * (y * z - x * w) as f32;
|
||||||
rotation_matrix.m33 = 1.0 - 2.0 * (x * x + y * y) as f32;
|
rotation_matrix.m33 = 1.0 - 2.0 * (x * x + y * y) as f32;
|
||||||
|
|
||||||
matrix = multiply(rotation_matrix, matrix);
|
matrix = multiply(rotation_matrix, matrix);
|
||||||
|
}
|
||||||
|
|
||||||
// Apply skew
|
// Apply skew
|
||||||
let mut temp = Matrix3D::identity();
|
{
|
||||||
if decomposed.skew.2 != 0.0 {
|
let mut temp = Matrix3D::identity();
|
||||||
temp.m32 = decomposed.skew.2;
|
if decomposed.skew.2 != 0.0 {
|
||||||
matrix = multiply(temp, matrix);
|
temp.m32 = decomposed.skew.2;
|
||||||
}
|
matrix = multiply(temp, matrix);
|
||||||
|
temp.m32 = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
if decomposed.skew.1 != 0.0 {
|
if decomposed.skew.1 != 0.0 {
|
||||||
temp.m32 = 0.0;
|
temp.m31 = decomposed.skew.1;
|
||||||
temp.m31 = decomposed.skew.1;
|
matrix = multiply(temp, matrix);
|
||||||
matrix = multiply(temp, matrix);
|
temp.m31 = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if decomposed.skew.0 != 0.0 {
|
if decomposed.skew.0 != 0.0 {
|
||||||
temp.m31 = 0.0;
|
temp.m21 = decomposed.skew.0;
|
||||||
temp.m21 = decomposed.skew.0;
|
matrix = multiply(temp, matrix);
|
||||||
matrix = multiply(temp, matrix);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply scale
|
// Apply scale
|
||||||
% for i in range(1, 4):
|
% for i in range(1, 4):
|
||||||
% for j in range(1, 4):
|
% for j in range(1, 5):
|
||||||
matrix.m${i}${j} *= decomposed.scale.${i - 1};
|
matrix.m${i}${j} *= decomposed.scale.${i - 1};
|
||||||
% endfor
|
% endfor
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
matrix
|
matrix
|
||||||
|
@ -2180,16 +2217,17 @@ impl From<MatrixDecomposed3D> for Matrix3D {
|
||||||
|
|
||||||
// Multiplication of two 4x4 matrices.
|
// Multiplication of two 4x4 matrices.
|
||||||
fn multiply(a: Matrix3D, b: Matrix3D) -> Matrix3D {
|
fn multiply(a: Matrix3D, b: Matrix3D) -> Matrix3D {
|
||||||
let mut a_clone = a;
|
Matrix3D {
|
||||||
% for i in range(1, 5):
|
% for i in range(1, 5):
|
||||||
% for j in range(1, 5):
|
% for j in range(1, 5):
|
||||||
a_clone.m${i}${j} = (a.m${i}1 * b.m1${j}) +
|
m${i}${j}:
|
||||||
(a.m${i}2 * b.m2${j}) +
|
a.m${i}1 * b.m1${j} +
|
||||||
(a.m${i}3 * b.m3${j}) +
|
a.m${i}2 * b.m2${j} +
|
||||||
(a.m${i}4 * b.m4${j});
|
a.m${i}3 * b.m3${j} +
|
||||||
% endfor
|
a.m${i}4 * b.m4${j},
|
||||||
% endfor
|
% endfor
|
||||||
a_clone
|
% endfor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Matrix3D {
|
impl Matrix3D {
|
||||||
|
@ -2227,11 +2265,22 @@ impl Matrix3D {
|
||||||
self.m11 * self.m22 * self.m33 * self.m44
|
self.m11 * self.m22 * self.m33 * self.m44
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inverse(&self) -> Option<Matrix3D> {
|
/// Transpose a matrix.
|
||||||
|
fn transpose(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
% for i in range(1, 5):
|
||||||
|
% for j in range(1, 5):
|
||||||
|
m${i}${j}: self.m${j}${i},
|
||||||
|
% endfor
|
||||||
|
% endfor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inverse(&self) -> Result<Matrix3D, ()> {
|
||||||
let mut det = self.determinant();
|
let mut det = self.determinant();
|
||||||
|
|
||||||
if det == 0.0 {
|
if det == 0.0 {
|
||||||
return None;
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
det = 1.0 / det;
|
det = 1.0 / det;
|
||||||
|
@ -2302,22 +2351,33 @@ impl Matrix3D {
|
||||||
self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33),
|
self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33),
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(x)
|
Ok(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Multiplies `pin * self`.
|
||||||
|
fn pre_mul_point4(&self, pin: &[f32; 4]) -> [f32; 4] {
|
||||||
|
[
|
||||||
|
% for i in range(1, 5):
|
||||||
|
pin[0] * self.m1${i} +
|
||||||
|
pin[1] * self.m2${i} +
|
||||||
|
pin[2] * self.m3${i} +
|
||||||
|
pin[3] * self.m4${i},
|
||||||
|
% endfor
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-transforms-2/#propdef-rotate>
|
/// <https://drafts.csswg.org/css-transforms-2/#propdef-rotate>
|
||||||
impl ComputedRotate {
|
impl ComputedRotate {
|
||||||
fn fill_unspecified(rotate: &ComputedRotate) -> Result<(Number, Number, Number, Angle), ()> {
|
fn resolve(rotate: &ComputedRotate) -> (Number, Number, Number, Angle) {
|
||||||
// According to the spec:
|
// According to the spec:
|
||||||
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
|
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
|
||||||
//
|
//
|
||||||
// If the axis is unspecified, it defaults to "0 0 1"
|
// If the axis is unspecified, it defaults to "0 0 1"
|
||||||
match *rotate {
|
match *rotate {
|
||||||
Rotate::None =>
|
Rotate::None => (0., 0., 1., Angle::zero()),
|
||||||
Ok((0., 0., 1., Angle::zero())),
|
Rotate::Rotate3D(rx, ry, rz, angle) => (rx, ry, rz, angle),
|
||||||
Rotate::Rotate3D(rx, ry, rz, angle) => Ok((rx, ry, rz, angle)),
|
Rotate::Rotate(angle) => (0., 0., 1., angle),
|
||||||
Rotate::Rotate(angle) => Ok((0., 0., 1., angle)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2329,11 +2389,13 @@ impl Animate for ComputedRotate {
|
||||||
other: &Self,
|
other: &Self,
|
||||||
procedure: Procedure,
|
procedure: Procedure,
|
||||||
) -> Result<Self, ()> {
|
) -> Result<Self, ()> {
|
||||||
let from = ComputedRotate::fill_unspecified(self)?;
|
let from = ComputedRotate::resolve(self);
|
||||||
let to = ComputedRotate::fill_unspecified(other)?;
|
let to = ComputedRotate::resolve(other);
|
||||||
|
|
||||||
let (fx, fy, fz, fa) = transform::get_normalized_vector_and_angle(from.0, from.1, from.2, from.3);
|
let (fx, fy, fz, fa) =
|
||||||
let (tx, ty, tz, ta) = transform::get_normalized_vector_and_angle(to.0, to.1, to.2, to.3);
|
transform::get_normalized_vector_and_angle(from.0, from.1, from.2, from.3);
|
||||||
|
let (tx, ty, tz, ta) =
|
||||||
|
transform::get_normalized_vector_and_angle(to.0, to.1, to.2, to.3);
|
||||||
if (fx, fy, fz) == (tx, ty, tz) {
|
if (fx, fy, fz) == (tx, ty, tz) {
|
||||||
return Ok(Rotate::Rotate3D(fx, fy, fz, fa.animate(&ta, procedure)?));
|
return Ok(Rotate::Rotate3D(fx, fy, fz, fa.animate(&ta, procedure)?));
|
||||||
}
|
}
|
||||||
|
@ -2344,11 +2406,12 @@ impl Animate for ComputedRotate {
|
||||||
let tq = Quaternion::from_direction_and_angle(&tv, ta.radians64());
|
let tq = Quaternion::from_direction_and_angle(&tv, ta.radians64());
|
||||||
|
|
||||||
let rq = Quaternion::animate(&fq, &tq, procedure)?;
|
let rq = Quaternion::animate(&fq, &tq, procedure)?;
|
||||||
let (x, y, z, angle) =
|
let (x, y, z, angle) = transform::get_normalized_vector_and_angle(
|
||||||
transform::get_normalized_vector_and_angle(rq.0 as f32,
|
rq.0 as f32,
|
||||||
rq.1 as f32,
|
rq.1 as f32,
|
||||||
rq.2 as f32,
|
rq.2 as f32,
|
||||||
rq.3.acos() as f32 *2.0);
|
rq.3.acos() as f32 * 2.0,
|
||||||
|
);
|
||||||
|
|
||||||
Ok(Rotate::Rotate3D(x, y, z, Angle::from_radians(angle)))
|
Ok(Rotate::Rotate3D(x, y, z, Angle::from_radians(angle)))
|
||||||
}
|
}
|
||||||
|
@ -2356,21 +2419,24 @@ impl Animate for ComputedRotate {
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-transforms-2/#propdef-translate>
|
/// <https://drafts.csswg.org/css-transforms-2/#propdef-translate>
|
||||||
impl ComputedTranslate {
|
impl ComputedTranslate {
|
||||||
fn fill_unspecified(translate: &ComputedTranslate)
|
fn resolve(
|
||||||
-> Result<(LengthOrPercentage, LengthOrPercentage, Length), ()> {
|
translate: &ComputedTranslate,
|
||||||
|
) -> (LengthOrPercentage, LengthOrPercentage, Length) {
|
||||||
// According to the spec:
|
// According to the spec:
|
||||||
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
|
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
|
||||||
//
|
//
|
||||||
// Unspecified translations default to 0px
|
// Unspecified translations default to 0px
|
||||||
match *translate {
|
match *translate {
|
||||||
Translate::None => {
|
Translate::None => {
|
||||||
Ok((LengthOrPercentage::Length(Length::zero()),
|
(
|
||||||
LengthOrPercentage::Length(Length::zero()),
|
LengthOrPercentage::Length(Length::zero()),
|
||||||
Length::zero()))
|
LengthOrPercentage::Length(Length::zero()),
|
||||||
|
Length::zero(),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
Translate::Translate3D(tx, ty, tz) => Ok((tx, ty, tz)),
|
Translate::Translate3D(tx, ty, tz) => (tx, ty, tz),
|
||||||
Translate::Translate(tx, ty) => Ok((tx, ty, Length::zero())),
|
Translate::Translate(tx, ty) => (tx, ty, Length::zero()),
|
||||||
Translate::TranslateX(tx) => Ok((tx, LengthOrPercentage::Length(Length::zero()), Length::zero())),
|
Translate::TranslateX(tx) => (tx, LengthOrPercentage::Length(Length::zero()), Length::zero()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2382,8 +2448,8 @@ impl Animate for ComputedTranslate {
|
||||||
other: &Self,
|
other: &Self,
|
||||||
procedure: Procedure,
|
procedure: Procedure,
|
||||||
) -> Result<Self, ()> {
|
) -> Result<Self, ()> {
|
||||||
let from = ComputedTranslate::fill_unspecified(self)?;
|
let from = ComputedTranslate::resolve(self);
|
||||||
let to = ComputedTranslate::fill_unspecified(other)?;
|
let to = ComputedTranslate::resolve(other);
|
||||||
|
|
||||||
Ok(Translate::Translate3D(from.0.animate(&to.0, procedure)?,
|
Ok(Translate::Translate3D(from.0.animate(&to.0, procedure)?,
|
||||||
from.1.animate(&to.1, procedure)?,
|
from.1.animate(&to.1, procedure)?,
|
||||||
|
@ -2393,17 +2459,16 @@ impl Animate for ComputedTranslate {
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-transforms-2/#propdef-scale>
|
/// <https://drafts.csswg.org/css-transforms-2/#propdef-scale>
|
||||||
impl ComputedScale {
|
impl ComputedScale {
|
||||||
fn fill_unspecified(scale: &ComputedScale)
|
fn resolve(scale: &ComputedScale) -> (Number, Number, Number) {
|
||||||
-> Result<(Number, Number, Number), ()> {
|
|
||||||
// According to the spec:
|
// According to the spec:
|
||||||
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
|
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
|
||||||
//
|
//
|
||||||
// Unspecified scales default to 1
|
// Unspecified scales default to 1
|
||||||
match *scale {
|
match *scale {
|
||||||
Scale::None => Ok((1.0, 1.0, 1.0)),
|
Scale::None => (1.0, 1.0, 1.0),
|
||||||
Scale::Scale3D(sx, sy, sz) => Ok((sx, sy, sz)),
|
Scale::Scale3D(sx, sy, sz) => (sx, sy, sz),
|
||||||
Scale::Scale(sx, sy) => Ok((sx, sy, 1.)),
|
Scale::Scale(sx, sy) => (sx, sy, 1.),
|
||||||
Scale::ScaleX(sx) => Ok((sx, 1., 1.)),
|
Scale::ScaleX(sx) => (sx, 1., 1.),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2415,17 +2480,21 @@ impl Animate for ComputedScale {
|
||||||
other: &Self,
|
other: &Self,
|
||||||
procedure: Procedure,
|
procedure: Procedure,
|
||||||
) -> Result<Self, ()> {
|
) -> Result<Self, ()> {
|
||||||
let from = ComputedScale::fill_unspecified(self)?;
|
let from = ComputedScale::resolve(self);
|
||||||
let to = ComputedScale::fill_unspecified(other)?;
|
let to = ComputedScale::resolve(other);
|
||||||
|
|
||||||
|
// FIXME(emilio, bug 1464791): why does this do something different than
|
||||||
|
// Scale3D / TransformOperation::Scale3D?
|
||||||
if procedure == Procedure::Add {
|
if procedure == Procedure::Add {
|
||||||
// scale(x1,y1,z1)*scale(x2,y2,z2) = scale(x1*x2, y1*y2, z1*z2)
|
// scale(x1,y1,z1)*scale(x2,y2,z2) = scale(x1*x2, y1*y2, z1*z2)
|
||||||
return Ok(Scale::Scale3D(from.0 * to.0, from.1 * to.1, from.2 * to.2));
|
return Ok(Scale::Scale3D(from.0 * to.0, from.1 * to.1, from.2 * to.2));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Scale::Scale3D(animate_multiplicative_factor(from.0, to.0, procedure)?,
|
Ok(Scale::Scale3D(
|
||||||
animate_multiplicative_factor(from.1, to.1, procedure)?,
|
animate_multiplicative_factor(from.0, to.0, procedure)?,
|
||||||
animate_multiplicative_factor(from.2, to.2, procedure)?))
|
animate_multiplicative_factor(from.1, to.1, procedure)?,
|
||||||
|
animate_multiplicative_factor(from.2, to.2, procedure)?,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2660,6 +2729,9 @@ impl ComputeSquaredDistance for ComputedTransformOperation {
|
||||||
_ if self.is_scale() && other.is_scale() => {
|
_ if self.is_scale() && other.is_scale() => {
|
||||||
self.to_scale_3d().compute_squared_distance(&other.to_scale_3d())
|
self.to_scale_3d().compute_squared_distance(&other.to_scale_3d())
|
||||||
}
|
}
|
||||||
|
_ if self.is_rotate() && other.is_rotate() => {
|
||||||
|
self.to_rotate_3d().compute_squared_distance(&other.to_rotate_3d())
|
||||||
|
}
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2668,27 +2740,16 @@ impl ComputeSquaredDistance for ComputedTransformOperation {
|
||||||
impl ComputeSquaredDistance for ComputedTransform {
|
impl ComputeSquaredDistance for ComputedTransform {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||||
let list1 = &self.0;
|
let squared_dist = self.0.squared_distance_with_zero(&other.0);
|
||||||
let list2 = &other.0;
|
|
||||||
|
|
||||||
let squared_dist: Result<SquaredDistance, _> = list1.iter().zip_longest(list2).map(|it| {
|
// Roll back to matrix interpolation if there is any Err(()) in the
|
||||||
match it {
|
// transform lists, such as mismatched transform functions.
|
||||||
EitherOrBoth::Both(this, other) => {
|
if squared_dist.is_err() {
|
||||||
this.compute_squared_distance(other)
|
|
||||||
},
|
|
||||||
EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => {
|
|
||||||
list.to_animated_zero()?.compute_squared_distance(list)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}).sum();
|
|
||||||
|
|
||||||
// Roll back to matrix interpolation if there is any Err(()) in the transform lists, such
|
|
||||||
// as mismatched transform functions.
|
|
||||||
if let Err(_) = squared_dist {
|
|
||||||
let matrix1: Matrix3D = self.to_transform_3d_matrix(None)?.0.into();
|
let matrix1: Matrix3D = self.to_transform_3d_matrix(None)?.0.into();
|
||||||
let matrix2: Matrix3D = other.to_transform_3d_matrix(None)?.0.into();
|
let matrix2: Matrix3D = other.to_transform_3d_matrix(None)?.0.into();
|
||||||
return matrix1.compute_squared_distance(&matrix2);
|
return matrix1.compute_squared_distance(&matrix2);
|
||||||
}
|
}
|
||||||
|
|
||||||
squared_dist
|
squared_dist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2828,7 +2889,7 @@ where
|
||||||
/// <https://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty>
|
/// <https://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty>
|
||||||
impl<L> Animate for SVGStrokeDashArray<L>
|
impl<L> Animate for SVGStrokeDashArray<L>
|
||||||
where
|
where
|
||||||
L: Clone + RepeatableListAnimatable,
|
L: Clone + Animate,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||||
|
@ -2838,7 +2899,22 @@ where
|
||||||
}
|
}
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other)) => {
|
(&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other)) => {
|
||||||
Ok(SVGStrokeDashArray::Values(this.animate(other, procedure)?))
|
Ok(SVGStrokeDashArray::Values(this.animate_repeatable_list(other, procedure)?))
|
||||||
|
},
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L> ComputeSquaredDistance for SVGStrokeDashArray<L>
|
||||||
|
where
|
||||||
|
L: ComputeSquaredDistance,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||||
|
match (self, other) {
|
||||||
|
(&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other)) => {
|
||||||
|
this.squared_distance_repeatable_list(other)
|
||||||
},
|
},
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
|
@ -2929,50 +3005,6 @@ impl ToAnimatedZero for AnimatedFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Animate for AnimatedFilterList {
|
|
||||||
#[inline]
|
|
||||||
fn animate(
|
|
||||||
&self,
|
|
||||||
other: &Self,
|
|
||||||
procedure: Procedure,
|
|
||||||
) -> Result<Self, ()> {
|
|
||||||
if procedure == Procedure::Add {
|
|
||||||
return Ok(AnimatedFilterList(
|
|
||||||
self.0.iter().chain(other.0.iter()).cloned().collect(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(AnimatedFilterList(self.0.iter().zip_longest(other.0.iter()).map(|it| {
|
|
||||||
match it {
|
|
||||||
EitherOrBoth::Both(this, other) => {
|
|
||||||
this.animate(other, procedure)
|
|
||||||
},
|
|
||||||
EitherOrBoth::Left(this) => {
|
|
||||||
this.animate(&this.to_animated_zero()?, procedure)
|
|
||||||
},
|
|
||||||
EitherOrBoth::Right(other) => {
|
|
||||||
other.to_animated_zero()?.animate(other, procedure)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}).collect::<Result<Vec<_>, _>>()?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ComputeSquaredDistance for AnimatedFilterList {
|
|
||||||
#[inline]
|
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
|
||||||
self.0.iter().zip_longest(other.0.iter()).map(|it| {
|
|
||||||
match it {
|
|
||||||
EitherOrBoth::Both(this, other) => {
|
|
||||||
this.compute_squared_distance(other)
|
|
||||||
},
|
|
||||||
EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => {
|
|
||||||
list.to_animated_zero()?.compute_squared_distance(list)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}).sum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A comparator to sort PropertyIds such that longhands are sorted before shorthands,
|
/// A comparator to sort PropertyIds such that longhands are sorted before shorthands,
|
||||||
/// shorthands with fewer components are sorted before shorthands with more components,
|
/// shorthands with fewer components are sorted before shorthands with more components,
|
||||||
/// and otherwise shorthands are sorted by IDL name as defined by [Web Animations][property-order].
|
/// and otherwise shorthands are sorted by IDL name as defined by [Web Animations][property-order].
|
||||||
|
|
|
@ -36,6 +36,7 @@ ${helpers.predefined_type("background-image", "ImageLayer",
|
||||||
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-" + axis,
|
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-" + axis,
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
vector=True,
|
vector=True,
|
||||||
|
vector_animation_type="repeatable_list",
|
||||||
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
|
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
|
||||||
)}
|
)}
|
||||||
% endfor
|
% endfor
|
||||||
|
@ -59,30 +60,38 @@ ${helpers.single_keyword("background-attachment",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")}
|
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")}
|
||||||
|
|
||||||
${helpers.single_keyword("background-clip",
|
${helpers.single_keyword(
|
||||||
"border-box padding-box content-box",
|
"background-clip",
|
||||||
extra_gecko_values="text",
|
"border-box padding-box content-box",
|
||||||
vector=True, extra_prefixes="webkit",
|
extra_gecko_values="text",
|
||||||
gecko_enum_prefix="StyleGeometryBox",
|
vector=True, extra_prefixes="webkit",
|
||||||
spec="https://drafts.csswg.org/css-backgrounds/#the-background-clip",
|
gecko_enum_prefix="StyleGeometryBox",
|
||||||
animation_value_type="discrete",
|
gecko_inexhaustive=True,
|
||||||
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")}
|
spec="https://drafts.csswg.org/css-backgrounds/#the-background-clip",
|
||||||
|
animation_value_type="discrete",
|
||||||
|
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
|
||||||
|
)}
|
||||||
|
|
||||||
${helpers.single_keyword("background-origin",
|
${helpers.single_keyword(
|
||||||
"padding-box border-box content-box",
|
"background-origin",
|
||||||
vector=True, extra_prefixes="webkit",
|
"padding-box border-box content-box",
|
||||||
gecko_enum_prefix="StyleGeometryBox",
|
vector=True, extra_prefixes="webkit",
|
||||||
spec="https://drafts.csswg.org/css-backgrounds/#the-background-origin",
|
gecko_enum_prefix="StyleGeometryBox",
|
||||||
animation_value_type="discrete",
|
gecko_inexhaustive=True,
|
||||||
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")}
|
spec="https://drafts.csswg.org/css-backgrounds/#the-background-origin",
|
||||||
|
animation_value_type="discrete",
|
||||||
|
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER"
|
||||||
|
)}
|
||||||
|
|
||||||
${helpers.predefined_type("background-size", "BackgroundSize",
|
${helpers.predefined_type(
|
||||||
|
"background-size",
|
||||||
|
"BackgroundSize",
|
||||||
initial_value="computed::BackgroundSize::auto()",
|
initial_value="computed::BackgroundSize::auto()",
|
||||||
initial_specified_value="specified::BackgroundSize::auto()",
|
initial_specified_value="specified::BackgroundSize::auto()",
|
||||||
spec="https://drafts.csswg.org/css-backgrounds/#the-background-size",
|
spec="https://drafts.csswg.org/css-backgrounds/#the-background-size",
|
||||||
vector=True,
|
vector=True,
|
||||||
|
vector_animation_type="repeatable_list",
|
||||||
animation_value_type="BackgroundSizeList",
|
animation_value_type="BackgroundSizeList",
|
||||||
need_animatable=True,
|
|
||||||
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
|
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
|
||||||
extra_prefixes="webkit")}
|
extra_prefixes="webkit")}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ ${helpers.predefined_type(
|
||||||
None,
|
None,
|
||||||
vector=True,
|
vector=True,
|
||||||
animation_value_type="AnimatedBoxShadowList",
|
animation_value_type="AnimatedBoxShadowList",
|
||||||
|
vector_animation_type="with_zero",
|
||||||
extra_prefixes="webkit",
|
extra_prefixes="webkit",
|
||||||
ignored_when_colors_disabled=True,
|
ignored_when_colors_disabled=True,
|
||||||
flags="APPLIES_TO_FIRST_LETTER",
|
flags="APPLIES_TO_FIRST_LETTER",
|
||||||
|
@ -45,6 +46,7 @@ ${helpers.predefined_type(
|
||||||
vector=True,
|
vector=True,
|
||||||
separator="Space",
|
separator="Space",
|
||||||
animation_value_type="AnimatedFilterList",
|
animation_value_type="AnimatedFilterList",
|
||||||
|
vector_animation_type="with_zero",
|
||||||
extra_prefixes="webkit",
|
extra_prefixes="webkit",
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
||||||
spec="https://drafts.fxtf.org/filters/#propdef-filter",
|
spec="https://drafts.fxtf.org/filters/#propdef-filter",
|
||||||
|
|
|
@ -192,6 +192,7 @@ ${helpers.predefined_type(
|
||||||
"SimpleShadow",
|
"SimpleShadow",
|
||||||
None,
|
None,
|
||||||
vector=True,
|
vector=True,
|
||||||
|
vector_animation_type="with_zero",
|
||||||
animation_value_type="AnimatedTextShadowList",
|
animation_value_type="AnimatedTextShadowList",
|
||||||
ignored_when_colors_disabled=True,
|
ignored_when_colors_disabled=True,
|
||||||
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
|
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
|
||||||
|
|
|
@ -43,10 +43,32 @@ ${helpers.single_keyword("-moz-user-focus",
|
||||||
|
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
"caret-color",
|
"caret-color",
|
||||||
"CaretColor",
|
"ColorOrAuto",
|
||||||
"generics::ui::CaretColor::Auto",
|
"Either::Second(Auto)",
|
||||||
spec="https://drafts.csswg.org/css-ui/#caret-color",
|
spec="https://drafts.csswg.org/css-ui/#caret-color",
|
||||||
animation_value_type="AnimatedCaretColor",
|
animation_value_type="AnimatedCaretColor",
|
||||||
ignored_when_colors_disabled=True,
|
ignored_when_colors_disabled=True,
|
||||||
products="gecko",
|
products="gecko",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
// Only scrollbar-face-color and scrollbar-track-color are added here.
|
||||||
|
// These two are the only common parts of scrollbar among Windows and
|
||||||
|
// macOS. We may or may not want to provide other properties to allow
|
||||||
|
// finer-grain control.
|
||||||
|
//
|
||||||
|
// NOTE The syntax in spec is currently `normal | <color>`, but I think
|
||||||
|
// reusing `auto | <color>` as `caret-color` makes more sense. See
|
||||||
|
// https://github.com/w3c/csswg-drafts/issues/2660
|
||||||
|
% for part in ["face", "track"]:
|
||||||
|
${helpers.predefined_type(
|
||||||
|
"scrollbar-%s-color" % part,
|
||||||
|
"ColorOrAuto",
|
||||||
|
"Either::Second(Auto)",
|
||||||
|
spec="https://drafts.csswg.org/css-scrollbars-1/#scrollbar-color-properties",
|
||||||
|
gecko_pref="layout.css.scrollbar-colors.enabled",
|
||||||
|
animation_value_type="ColorOrAuto",
|
||||||
|
ignored_when_colors_disabled=True,
|
||||||
|
enabled_in="chrome",
|
||||||
|
products="gecko",
|
||||||
|
)}
|
||||||
|
% endfor
|
||||||
|
|
|
@ -103,49 +103,49 @@ ${helpers.predefined_type(
|
||||||
initial_specified_value="specified::PositionComponent::Center",
|
initial_specified_value="specified::PositionComponent::Center",
|
||||||
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position",
|
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position",
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
|
vector_animation_type="repeatable_list",
|
||||||
vector=True,
|
vector=True,
|
||||||
)}
|
)}
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
${helpers.single_keyword("mask-clip",
|
${helpers.single_keyword(
|
||||||
"border-box content-box padding-box",
|
"mask-clip",
|
||||||
extra_gecko_values="fill-box stroke-box view-box no-clip",
|
"border-box content-box padding-box",
|
||||||
vector=True,
|
extra_gecko_values="fill-box stroke-box view-box no-clip",
|
||||||
products="gecko",
|
vector=True,
|
||||||
extra_prefixes="webkit",
|
products="gecko",
|
||||||
gecko_enum_prefix="StyleGeometryBox",
|
extra_prefixes="webkit",
|
||||||
animation_value_type="discrete",
|
gecko_enum_prefix="StyleGeometryBox",
|
||||||
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-clip")}
|
gecko_inexhaustive=True,
|
||||||
|
animation_value_type="discrete",
|
||||||
|
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-clip",
|
||||||
|
)}
|
||||||
|
|
||||||
${helpers.single_keyword("mask-origin",
|
${helpers.single_keyword(
|
||||||
"border-box content-box padding-box",
|
"mask-origin",
|
||||||
extra_gecko_values="fill-box stroke-box view-box",
|
"border-box content-box padding-box",
|
||||||
vector=True,
|
extra_gecko_values="fill-box stroke-box view-box",
|
||||||
products="gecko",
|
vector=True,
|
||||||
extra_prefixes="webkit",
|
products="gecko",
|
||||||
gecko_enum_prefix="StyleGeometryBox",
|
extra_prefixes="webkit",
|
||||||
animation_value_type="discrete",
|
gecko_enum_prefix="StyleGeometryBox",
|
||||||
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-origin")}
|
gecko_inexhaustive=True,
|
||||||
|
animation_value_type="discrete",
|
||||||
|
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-origin",
|
||||||
|
)}
|
||||||
|
|
||||||
<%helpers:longhand name="mask-size" products="gecko" animation_value_type="ComputedValue" extra_prefixes="webkit"
|
${helpers.predefined_type(
|
||||||
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-size">
|
"mask-size",
|
||||||
use properties::longhands::background_size;
|
"background::BackgroundSize",
|
||||||
pub use ::properties::longhands::background_size::SpecifiedValue;
|
"computed::BackgroundSize::auto()",
|
||||||
pub use ::properties::longhands::background_size::single_value as single_value;
|
initial_specified_value="specified::BackgroundSize::auto()",
|
||||||
pub use ::properties::longhands::background_size::computed_value as computed_value;
|
products="gecko",
|
||||||
|
extra_prefixes="webkit",
|
||||||
#[inline]
|
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-size",
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
animation_value_type="MaskSizeList",
|
||||||
background_size::get_initial_value()
|
vector=True,
|
||||||
}
|
vector_animation_type="repeatable_list",
|
||||||
|
)}
|
||||||
pub fn parse<'i, 't>(
|
|
||||||
context: &ParserContext,
|
|
||||||
input: &mut Parser<'i, 't>,
|
|
||||||
) -> Result<SpecifiedValue, ParseError<'i>> {
|
|
||||||
background_size::parse(context, input)
|
|
||||||
}
|
|
||||||
</%helpers:longhand>
|
|
||||||
|
|
||||||
${helpers.single_keyword("mask-composite",
|
${helpers.single_keyword("mask-composite",
|
||||||
"add subtract intersect exclude",
|
"add subtract intersect exclude",
|
||||||
|
|
|
@ -2216,12 +2216,13 @@ pub mod style_structs {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_${longhand.ident}<I>(&mut self, v: I)
|
pub fn set_${longhand.ident}<I>(&mut self, v: I)
|
||||||
where I: IntoIterator<Item = longhands::${longhand.ident}
|
where
|
||||||
::computed_value::single_value::T>,
|
I: IntoIterator<Item = longhands::${longhand.ident}
|
||||||
I::IntoIter: ExactSizeIterator
|
::computed_value::single_value::T>,
|
||||||
|
I::IntoIter: ExactSizeIterator
|
||||||
{
|
{
|
||||||
self.${longhand.ident} = longhands::${longhand.ident}::computed_value
|
self.${longhand.ident} = longhands::${longhand.ident}::computed_value
|
||||||
::T(v.into_iter().collect());
|
::List(v.into_iter().collect());
|
||||||
}
|
}
|
||||||
% elif longhand.ident == "display":
|
% elif longhand.ident == "display":
|
||||||
/// Set `display`.
|
/// Set `display`.
|
||||||
|
@ -2404,7 +2405,7 @@ pub mod style_structs {
|
||||||
pub fn clone_${longhand.ident}(
|
pub fn clone_${longhand.ident}(
|
||||||
&self,
|
&self,
|
||||||
) -> longhands::${longhand.ident}::computed_value::T {
|
) -> longhands::${longhand.ident}::computed_value::T {
|
||||||
longhands::${longhand.ident}::computed_value::T(
|
longhands::${longhand.ident}::computed_value::List(
|
||||||
self.${longhand.ident}_iter().collect()
|
self.${longhand.ident}_iter().collect()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2536,13 +2537,6 @@ impl ComputedValues {
|
||||||
self.visited_style.as_ref().and_then(|s| s.rules.as_ref())
|
self.visited_style.as_ref().and_then(|s| s.rules.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether we're in a display: none subtree.
|
|
||||||
pub fn is_in_display_none_subtree(&self) -> bool {
|
|
||||||
use properties::computed_value_flags::ComputedValueFlags;
|
|
||||||
|
|
||||||
self.flags.contains(ComputedValueFlags::IS_IN_DISPLAY_NONE_SUBTREE)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference to the custom properties map (if one exists).
|
/// Gets a reference to the custom properties map (if one exists).
|
||||||
pub fn custom_properties(&self) -> Option<<&Arc<::custom_properties::CustomPropertiesMap>> {
|
pub fn custom_properties(&self) -> Option<<&Arc<::custom_properties::CustomPropertiesMap>> {
|
||||||
self.custom_properties.as_ref()
|
self.custom_properties.as_ref()
|
||||||
|
@ -3198,6 +3192,7 @@ impl<'a> StyleBuilder<'a> {
|
||||||
% endif
|
% endif
|
||||||
% endif
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
|
<% del property %>
|
||||||
|
|
||||||
/// Inherits style from the parent element, accounting for the default
|
/// Inherits style from the parent element, accounting for the default
|
||||||
/// computed values that need to be provided as well.
|
/// computed values that need to be provided as well.
|
||||||
|
@ -3255,7 +3250,7 @@ impl<'a> StyleBuilder<'a> {
|
||||||
|
|
||||||
/// Gets a mutable view of the current `${style_struct.name}` style.
|
/// Gets a mutable view of the current `${style_struct.name}` style.
|
||||||
pub fn mutate_${style_struct.name_lower}(&mut self) -> &mut style_structs::${style_struct.name} {
|
pub fn mutate_${style_struct.name_lower}(&mut self) -> &mut style_structs::${style_struct.name} {
|
||||||
% if not property.style_struct.inherited:
|
% if not style_struct.inherited:
|
||||||
self.modified_reset = true;
|
self.modified_reset = true;
|
||||||
% endif
|
% endif
|
||||||
self.${style_struct.ident}.mutate()
|
self.${style_struct.ident}.mutate()
|
||||||
|
@ -3263,7 +3258,7 @@ impl<'a> StyleBuilder<'a> {
|
||||||
|
|
||||||
/// Gets a mutable view of the current `${style_struct.name}` style.
|
/// Gets a mutable view of the current `${style_struct.name}` style.
|
||||||
pub fn take_${style_struct.name_lower}(&mut self) -> UniqueArc<style_structs::${style_struct.name}> {
|
pub fn take_${style_struct.name_lower}(&mut self) -> UniqueArc<style_structs::${style_struct.name}> {
|
||||||
% if not property.style_struct.inherited:
|
% if not style_struct.inherited:
|
||||||
self.modified_reset = true;
|
self.modified_reset = true;
|
||||||
% endif
|
% endif
|
||||||
self.${style_struct.ident}.take()
|
self.${style_struct.ident}.take()
|
||||||
|
@ -3287,6 +3282,7 @@ impl<'a> StyleBuilder<'a> {
|
||||||
StyleStructRef::Borrowed(self.reset_style.${style_struct.name_lower}_arc());
|
StyleStructRef::Borrowed(self.reset_style.${style_struct.name_lower}_arc());
|
||||||
}
|
}
|
||||||
% endfor
|
% endfor
|
||||||
|
<% del style_struct %>
|
||||||
|
|
||||||
/// Returns whether this computed style represents a floated object.
|
/// Returns whether this computed style represents a floated object.
|
||||||
pub fn floated(&self) -> bool {
|
pub fn floated(&self) -> bool {
|
||||||
|
|
|
@ -188,8 +188,10 @@
|
||||||
use values::specified::position::Position;
|
use values::specified::position::Position;
|
||||||
use parser::Parse;
|
use parser::Parse;
|
||||||
|
|
||||||
pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
|
pub fn parse_value<'i, 't>(
|
||||||
-> Result<Longhands, ParseError<'i>> {
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Longhands, ParseError<'i>> {
|
||||||
// Vec grows from 0 to 4 by default on first push(). So allocate with
|
// Vec grows from 0 to 4 by default on first push(). So allocate with
|
||||||
// capacity 1, so in the common case of only one item we don't way
|
// capacity 1, so in the common case of only one item we don't way
|
||||||
// overallocate. Note that we always push at least one item if parsing
|
// overallocate. Note that we always push at least one item if parsing
|
||||||
|
@ -205,7 +207,8 @@
|
||||||
any = true;
|
any = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
if any == false {
|
|
||||||
|
if !any {
|
||||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -204,12 +204,6 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
||||||
.insert(ComputedValueFlags::HAS_TEXT_DECORATION_LINES);
|
.insert(ComputedValueFlags::HAS_TEXT_DECORATION_LINES);
|
||||||
}
|
}
|
||||||
|
|
||||||
if display == Display::None {
|
|
||||||
self.style
|
|
||||||
.flags
|
|
||||||
.insert(ComputedValueFlags::IS_IN_DISPLAY_NONE_SUBTREE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.style.is_pseudo_element() {
|
if self.style.is_pseudo_element() {
|
||||||
self.style
|
self.style
|
||||||
.flags
|
.flags
|
||||||
|
|
|
@ -4,13 +4,8 @@
|
||||||
|
|
||||||
//! Animated types for CSS values related to effects.
|
//! Animated types for CSS values related to effects.
|
||||||
|
|
||||||
use properties::longhands::box_shadow::computed_value::T as ComputedBoxShadowList;
|
|
||||||
use properties::longhands::filter::computed_value::T as ComputedFilterList;
|
|
||||||
use properties::longhands::text_shadow::computed_value::T as ComputedTextShadowList;
|
|
||||||
use std::cmp;
|
|
||||||
#[cfg(not(feature = "gecko"))]
|
#[cfg(not(feature = "gecko"))]
|
||||||
use values::Impossible;
|
use values::Impossible;
|
||||||
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
|
|
||||||
use values::animated::color::RGBA;
|
use values::animated::color::RGBA;
|
||||||
use values::computed::{Angle, Number};
|
use values::computed::{Angle, Number};
|
||||||
use values::computed::length::Length;
|
use values::computed::length::Length;
|
||||||
|
@ -21,27 +16,9 @@ use values::generics::effects::BoxShadow as GenericBoxShadow;
|
||||||
use values::generics::effects::Filter as GenericFilter;
|
use values::generics::effects::Filter as GenericFilter;
|
||||||
use values::generics::effects::SimpleShadow as GenericSimpleShadow;
|
use values::generics::effects::SimpleShadow as GenericSimpleShadow;
|
||||||
|
|
||||||
/// An animated value for the `box-shadow` property.
|
|
||||||
pub type BoxShadowList = ShadowList<BoxShadow>;
|
|
||||||
|
|
||||||
/// An animated value for the `text-shadow` property.
|
|
||||||
pub type TextShadowList = ShadowList<SimpleShadow>;
|
|
||||||
|
|
||||||
/// An animated value for shadow lists.
|
|
||||||
///
|
|
||||||
/// <https://drafts.csswg.org/css-transitions/#animtype-shadow-list>
|
|
||||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ShadowList<Shadow>(Vec<Shadow>);
|
|
||||||
|
|
||||||
/// An animated value for a single `box-shadow`.
|
/// An animated value for a single `box-shadow`.
|
||||||
pub type BoxShadow = GenericBoxShadow<Option<RGBA>, Length, Length, Length>;
|
pub type BoxShadow = GenericBoxShadow<Option<RGBA>, Length, Length, Length>;
|
||||||
|
|
||||||
/// An animated value for the `filter` property.
|
|
||||||
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct FilterList(pub Vec<Filter>);
|
|
||||||
|
|
||||||
/// An animated value for a single `filter`.
|
/// An animated value for a single `filter`.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow, ComputedUrl>;
|
pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow, ComputedUrl>;
|
||||||
|
@ -53,86 +30,6 @@ pub type Filter = GenericFilter<Angle, Number, Length, Impossible, Impossible>;
|
||||||
/// An animated value for the `drop-shadow()` filter.
|
/// An animated value for the `drop-shadow()` filter.
|
||||||
pub type SimpleShadow = GenericSimpleShadow<Option<RGBA>, Length, Length>;
|
pub type SimpleShadow = GenericSimpleShadow<Option<RGBA>, Length, Length>;
|
||||||
|
|
||||||
impl ToAnimatedValue for ComputedBoxShadowList {
|
|
||||||
type AnimatedValue = BoxShadowList;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_animated_value(self) -> Self::AnimatedValue {
|
|
||||||
ShadowList(self.0.to_animated_value())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
|
||||||
ComputedBoxShadowList(ToAnimatedValue::from_animated_value(animated.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> Animate for ShadowList<S>
|
|
||||||
where
|
|
||||||
S: Animate + Clone + ToAnimatedZero,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
|
||||||
if procedure == Procedure::Add {
|
|
||||||
return Ok(ShadowList(self.0.iter().chain(&other.0).cloned().collect()));
|
|
||||||
}
|
|
||||||
// FIXME(nox): Use itertools here, to avoid the need for `unreachable!`.
|
|
||||||
let max_len = cmp::max(self.0.len(), other.0.len());
|
|
||||||
let mut shadows = Vec::with_capacity(max_len);
|
|
||||||
for i in 0..max_len {
|
|
||||||
shadows.push(match (self.0.get(i), other.0.get(i)) {
|
|
||||||
(Some(shadow), Some(other)) => shadow.animate(other, procedure)?,
|
|
||||||
(Some(shadow), None) => shadow.animate(&shadow.to_animated_zero()?, procedure)?,
|
|
||||||
(None, Some(shadow)) => shadow.to_animated_zero()?.animate(shadow, procedure)?,
|
|
||||||
(None, None) => unreachable!(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Ok(ShadowList(shadows))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> ComputeSquaredDistance for ShadowList<S>
|
|
||||||
where
|
|
||||||
S: ComputeSquaredDistance + ToAnimatedZero,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
|
||||||
use itertools::{EitherOrBoth, Itertools};
|
|
||||||
|
|
||||||
self.0
|
|
||||||
.iter()
|
|
||||||
.zip_longest(other.0.iter())
|
|
||||||
.map(|it| match it {
|
|
||||||
EitherOrBoth::Both(from, to) => from.compute_squared_distance(to),
|
|
||||||
EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => {
|
|
||||||
list.compute_squared_distance(&list.to_animated_zero()?)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.sum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> ToAnimatedZero for ShadowList<S> {
|
|
||||||
#[inline]
|
|
||||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
|
||||||
Ok(ShadowList(vec![]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToAnimatedValue for ComputedTextShadowList {
|
|
||||||
type AnimatedValue = TextShadowList;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_animated_value(self) -> Self::AnimatedValue {
|
|
||||||
ShadowList(self.0.to_animated_value())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
|
||||||
ComputedTextShadowList(ToAnimatedValue::from_animated_value(animated.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ComputeSquaredDistance for BoxShadow {
|
impl ComputeSquaredDistance for BoxShadow {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||||
|
@ -143,24 +40,3 @@ impl ComputeSquaredDistance for BoxShadow {
|
||||||
self.spread.compute_squared_distance(&other.spread)?)
|
self.spread.compute_squared_distance(&other.spread)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToAnimatedValue for ComputedFilterList {
|
|
||||||
type AnimatedValue = FilterList;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_animated_value(self) -> Self::AnimatedValue {
|
|
||||||
FilterList(self.0.to_animated_value())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
|
||||||
ComputedFilterList(ToAnimatedValue::from_animated_value(animated.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToAnimatedZero for FilterList {
|
|
||||||
#[inline]
|
|
||||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
|
||||||
Ok(FilterList(vec![]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ use values::computed::Angle as ComputedAngle;
|
||||||
use values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
|
use values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
|
||||||
use values::computed::MaxLength as ComputedMaxLength;
|
use values::computed::MaxLength as ComputedMaxLength;
|
||||||
use values::computed::MozLength as ComputedMozLength;
|
use values::computed::MozLength as ComputedMozLength;
|
||||||
|
use values::computed::length::CalcLengthOrPercentage;
|
||||||
use values::computed::url::ComputedUrl;
|
use values::computed::url::ComputedUrl;
|
||||||
|
|
||||||
pub mod color;
|
pub mod color;
|
||||||
|
@ -257,6 +258,7 @@ macro_rules! trivial_to_animated_value {
|
||||||
}
|
}
|
||||||
|
|
||||||
trivial_to_animated_value!(Au);
|
trivial_to_animated_value!(Au);
|
||||||
|
trivial_to_animated_value!(CalcLengthOrPercentage);
|
||||||
trivial_to_animated_value!(ComputedAngle);
|
trivial_to_animated_value!(ComputedAngle);
|
||||||
trivial_to_animated_value!(ComputedUrl);
|
trivial_to_animated_value!(ComputedUrl);
|
||||||
trivial_to_animated_value!(bool);
|
trivial_to_animated_value!(bool);
|
||||||
|
|
|
@ -4,85 +4,27 @@
|
||||||
|
|
||||||
//! Computed types for CSS values related to backgrounds.
|
//! Computed types for CSS values related to backgrounds.
|
||||||
|
|
||||||
use properties::animated_properties::RepeatableListAnimatable;
|
|
||||||
use properties::longhands::background_size::computed_value::T as BackgroundSizeList;
|
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use style_traits::{CssWriter, ToCss};
|
use style_traits::{CssWriter, ToCss};
|
||||||
use values::animated::{ToAnimatedValue, ToAnimatedZero};
|
|
||||||
use values::computed::{Context, ToComputedValue};
|
use values::computed::{Context, ToComputedValue};
|
||||||
use values::computed::length::LengthOrPercentageOrAuto;
|
use values::computed::length::NonNegativeLengthOrPercentageOrAuto;
|
||||||
use values::generics::background::BackgroundSize as GenericBackgroundSize;
|
use values::generics::background::BackgroundSize as GenericBackgroundSize;
|
||||||
use values::specified::background::BackgroundRepeat as SpecifiedBackgroundRepeat;
|
use values::specified::background::BackgroundRepeat as SpecifiedBackgroundRepeat;
|
||||||
use values::specified::background::BackgroundRepeatKeyword;
|
use values::specified::background::BackgroundRepeatKeyword;
|
||||||
|
|
||||||
/// A computed value for the `background-size` property.
|
/// A computed value for the `background-size` property.
|
||||||
pub type BackgroundSize = GenericBackgroundSize<LengthOrPercentageOrAuto>;
|
pub type BackgroundSize = GenericBackgroundSize<NonNegativeLengthOrPercentageOrAuto>;
|
||||||
|
|
||||||
impl BackgroundSize {
|
impl BackgroundSize {
|
||||||
/// Returns `auto auto`.
|
/// Returns `auto auto`.
|
||||||
pub fn auto() -> Self {
|
pub fn auto() -> Self {
|
||||||
GenericBackgroundSize::Explicit {
|
GenericBackgroundSize::Explicit {
|
||||||
width: LengthOrPercentageOrAuto::Auto,
|
width: NonNegativeLengthOrPercentageOrAuto::auto(),
|
||||||
height: LengthOrPercentageOrAuto::Auto,
|
height: NonNegativeLengthOrPercentageOrAuto::auto(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RepeatableListAnimatable for BackgroundSize {}
|
|
||||||
|
|
||||||
impl ToAnimatedZero for BackgroundSize {
|
|
||||||
#[inline]
|
|
||||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToAnimatedValue for BackgroundSize {
|
|
||||||
type AnimatedValue = Self;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_animated_value(self) -> Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
|
||||||
use values::computed::{Length, Percentage};
|
|
||||||
let clamp_animated_value = |value: LengthOrPercentageOrAuto| -> LengthOrPercentageOrAuto {
|
|
||||||
match value {
|
|
||||||
LengthOrPercentageOrAuto::Length(len) => {
|
|
||||||
LengthOrPercentageOrAuto::Length(Length::new(len.px().max(0.)))
|
|
||||||
},
|
|
||||||
LengthOrPercentageOrAuto::Percentage(percent) => {
|
|
||||||
LengthOrPercentageOrAuto::Percentage(Percentage(percent.0.max(0.)))
|
|
||||||
},
|
|
||||||
_ => value,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match animated {
|
|
||||||
GenericBackgroundSize::Explicit { width, height } => GenericBackgroundSize::Explicit {
|
|
||||||
width: clamp_animated_value(width),
|
|
||||||
height: clamp_animated_value(height),
|
|
||||||
},
|
|
||||||
_ => animated,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToAnimatedValue for BackgroundSizeList {
|
|
||||||
type AnimatedValue = Self;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_animated_value(self) -> Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
|
||||||
BackgroundSizeList(ToAnimatedValue::from_animated_value(animated.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The computed value of the `background-repeat` property:
|
/// The computed value of the `background-repeat` property:
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-backgrounds/#the-background-repeat
|
/// https://drafts.csswg.org/css-backgrounds/#the-background-repeat
|
||||||
|
|
|
@ -474,7 +474,7 @@ impl SingleFontFamily {
|
||||||
FontFamilyType::eFamily_cursive => SingleFontFamily::Generic(atom!("cursive")),
|
FontFamilyType::eFamily_cursive => SingleFontFamily::Generic(atom!("cursive")),
|
||||||
FontFamilyType::eFamily_fantasy => SingleFontFamily::Generic(atom!("fantasy")),
|
FontFamilyType::eFamily_fantasy => SingleFontFamily::Generic(atom!("fantasy")),
|
||||||
FontFamilyType::eFamily_moz_fixed => {
|
FontFamilyType::eFamily_moz_fixed => {
|
||||||
SingleFontFamily::Generic(Atom::from("-moz-fixed"))
|
SingleFontFamily::Generic(atom!("-moz-fixed"))
|
||||||
},
|
},
|
||||||
FontFamilyType::eFamily_named => {
|
FontFamilyType::eFamily_named => {
|
||||||
let name = Atom::from(&*family.mName);
|
let name = Atom::from(&*family.mName);
|
||||||
|
|
|
@ -324,8 +324,8 @@ impl ToComputedValue for specified::CalcLengthOrPercentage {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[animate(fallback = "Self::animate_fallback")]
|
#[animate(fallback = "Self::animate_fallback")]
|
||||||
#[css(derive_debug)]
|
#[css(derive_debug)]
|
||||||
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq, ToAnimatedZero,
|
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq,
|
||||||
ToCss)]
|
ToAnimatedValue, ToAnimatedZero, ToCss)]
|
||||||
#[distance(fallback = "Self::compute_squared_distance_fallback")]
|
#[distance(fallback = "Self::compute_squared_distance_fallback")]
|
||||||
pub enum LengthOrPercentage {
|
pub enum LengthOrPercentage {
|
||||||
Length(Length),
|
Length(Length),
|
||||||
|
|
|
@ -78,7 +78,7 @@ pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle, TextOve
|
||||||
pub use self::time::Time;
|
pub use self::time::Time;
|
||||||
pub use self::transform::{Rotate, Scale, TimingFunction, Transform, TransformOperation};
|
pub use self::transform::{Rotate, Scale, TimingFunction, Transform, TransformOperation};
|
||||||
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
|
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
|
||||||
pub use self::ui::{CaretColor, Cursor, MozForceBrokenImageIcon};
|
pub use self::ui::{ColorOrAuto, Cursor, MozForceBrokenImageIcon};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use self::ui::CursorImage;
|
pub use self::ui::CursorImage;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ use values::generics::NonNegative;
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||||
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default,
|
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default,
|
||||||
MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo,
|
MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo,
|
||||||
ToAnimatedZero, ToComputedValue)]
|
ToAnimatedValue, ToAnimatedZero, ToComputedValue)]
|
||||||
pub struct Percentage(pub CSSFloat);
|
pub struct Percentage(pub CSSFloat);
|
||||||
|
|
||||||
impl Percentage {
|
impl Percentage {
|
||||||
|
|
|
@ -151,6 +151,27 @@ impl TransformOperation {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert to a Rotate3D.
|
||||||
|
///
|
||||||
|
/// Must be called on a Rotate function.
|
||||||
|
pub fn to_rotate_3d(&self) -> Self {
|
||||||
|
match *self {
|
||||||
|
generic::TransformOperation::Rotate3D(..) => self.clone(),
|
||||||
|
generic::TransformOperation::RotateZ(ref angle) |
|
||||||
|
generic::TransformOperation::Rotate(ref angle) => {
|
||||||
|
generic::TransformOperation::Rotate3D(0., 0., 1., angle.clone())
|
||||||
|
}
|
||||||
|
generic::TransformOperation::RotateX(ref angle) => {
|
||||||
|
generic::TransformOperation::Rotate3D(1., 0., 0., angle.clone())
|
||||||
|
}
|
||||||
|
generic::TransformOperation::RotateY(ref angle) => {
|
||||||
|
generic::TransformOperation::Rotate3D(0., 1., 0., angle.clone())
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert to a Scale3D.
|
/// Convert to a Scale3D.
|
||||||
///
|
///
|
||||||
/// Must be called on a Scale function
|
/// Must be called on a Scale function
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
//! Computed values for UI properties
|
//! Computed values for UI properties
|
||||||
|
|
||||||
|
use values::{Auto, Either};
|
||||||
use values::computed::Number;
|
use values::computed::Number;
|
||||||
use values::computed::color::Color;
|
use values::computed::color::Color;
|
||||||
use values::computed::url::ComputedImageUrl;
|
use values::computed::url::ComputedImageUrl;
|
||||||
|
@ -11,8 +12,8 @@ use values::generics::ui as generics;
|
||||||
|
|
||||||
pub use values::specified::ui::MozForceBrokenImageIcon;
|
pub use values::specified::ui::MozForceBrokenImageIcon;
|
||||||
|
|
||||||
/// A computed value for the `caret-color` property.
|
/// auto | <color>
|
||||||
pub type CaretColor = generics::CaretColor<Color>;
|
pub type ColorOrAuto = Either<Color, Auto>;
|
||||||
|
|
||||||
/// A computed value for the `cursor` property.
|
/// A computed value for the `cursor` property.
|
||||||
pub type Cursor = generics::Cursor<CursorImage>;
|
pub type Cursor = generics::Cursor<CursorImage>;
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
/// A generic value for the `background-size` property.
|
/// A generic value for the `background-size` property.
|
||||||
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
|
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
|
||||||
PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
|
PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero,
|
||||||
|
ToComputedValue, ToCss)]
|
||||||
pub enum BackgroundSize<LengthOrPercentageOrAuto> {
|
pub enum BackgroundSize<LengthOrPercentageOrAuto> {
|
||||||
/// `<width> <height>`
|
/// `<width> <height>`
|
||||||
Explicit {
|
Explicit {
|
||||||
|
|
|
@ -202,14 +202,13 @@ pub enum SVGLength<LengthType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generic value for stroke-dasharray.
|
/// Generic value for stroke-dasharray.
|
||||||
#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq,
|
#[derive(Clone, Debug, MallocSizeOf, PartialEq,
|
||||||
SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)]
|
SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)]
|
||||||
pub enum SVGStrokeDashArray<LengthType> {
|
pub enum SVGStrokeDashArray<LengthType> {
|
||||||
/// `[ <length> | <percentage> | <number> ]#`
|
/// `[ <length> | <percentage> | <number> ]#`
|
||||||
#[css(comma)]
|
#[css(comma)]
|
||||||
Values(
|
Values(
|
||||||
#[css(if_empty = "none", iterable)]
|
#[css(if_empty = "none", iterable)]
|
||||||
#[distance(field_bound)]
|
|
||||||
Vec<LengthType>,
|
Vec<LengthType>,
|
||||||
),
|
),
|
||||||
/// `context-value`
|
/// `context-value`
|
||||||
|
|
|
@ -276,6 +276,19 @@ pub struct Transform<T>(#[css(if_empty = "none", iterable)] pub Vec<T>);
|
||||||
impl<Angle, Number, Length, Integer, LengthOrPercentage>
|
impl<Angle, Number, Length, Integer, LengthOrPercentage>
|
||||||
TransformOperation<Angle, Number, Length, Integer, LengthOrPercentage>
|
TransformOperation<Angle, Number, Length, Integer, LengthOrPercentage>
|
||||||
{
|
{
|
||||||
|
/// Check if it is any rotate function.
|
||||||
|
pub fn is_rotate(&self) -> bool {
|
||||||
|
use self::TransformOperation::*;
|
||||||
|
matches!(
|
||||||
|
*self,
|
||||||
|
Rotate(..) |
|
||||||
|
Rotate3D(..) |
|
||||||
|
RotateX(..) |
|
||||||
|
RotateY(..) |
|
||||||
|
RotateZ(..)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if it is any translate function
|
/// Check if it is any translate function
|
||||||
pub fn is_translate(&self) -> bool {
|
pub fn is_translate(&self) -> bool {
|
||||||
use self::TransformOperation::*;
|
use self::TransformOperation::*;
|
||||||
|
|
|
@ -8,17 +8,6 @@ use std::fmt::{self, Write};
|
||||||
use style_traits::{CssWriter, ToCss};
|
use style_traits::{CssWriter, ToCss};
|
||||||
use style_traits::cursor::CursorKind;
|
use style_traits::cursor::CursorKind;
|
||||||
|
|
||||||
/// A generic value for the `caret-color` property.
|
|
||||||
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
|
|
||||||
PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero,
|
|
||||||
ToComputedValue, ToCss)]
|
|
||||||
pub enum CaretColor<Color> {
|
|
||||||
/// An explicit color.
|
|
||||||
Color(Color),
|
|
||||||
/// The keyword `auto`.
|
|
||||||
Auto,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A generic value for the `cursor` property.
|
/// A generic value for the `cursor` property.
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-ui/#cursor
|
/// https://drafts.csswg.org/css-ui/#cursor
|
||||||
|
|
|
@ -9,30 +9,25 @@ use parser::{Parse, ParserContext};
|
||||||
use selectors::parser::SelectorParseErrorKind;
|
use selectors::parser::SelectorParseErrorKind;
|
||||||
use style_traits::ParseError;
|
use style_traits::ParseError;
|
||||||
use values::generics::background::BackgroundSize as GenericBackgroundSize;
|
use values::generics::background::BackgroundSize as GenericBackgroundSize;
|
||||||
use values::specified::length::LengthOrPercentageOrAuto;
|
use values::specified::length::NonNegativeLengthOrPercentageOrAuto;
|
||||||
|
|
||||||
/// A specified value for the `background-size` property.
|
/// A specified value for the `background-size` property.
|
||||||
pub type BackgroundSize = GenericBackgroundSize<LengthOrPercentageOrAuto>;
|
pub type BackgroundSize = GenericBackgroundSize<NonNegativeLengthOrPercentageOrAuto>;
|
||||||
|
|
||||||
impl Parse for BackgroundSize {
|
impl Parse for BackgroundSize {
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
if let Ok(width) = input.try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i)) {
|
if let Ok(width) = input.try(|i| NonNegativeLengthOrPercentageOrAuto::parse(context, i)) {
|
||||||
let height = input
|
let height = input
|
||||||
.try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i))
|
.try(|i| NonNegativeLengthOrPercentageOrAuto::parse(context, i))
|
||||||
.unwrap_or(LengthOrPercentageOrAuto::Auto);
|
.unwrap_or(NonNegativeLengthOrPercentageOrAuto::auto());
|
||||||
return Ok(GenericBackgroundSize::Explicit { width, height });
|
return Ok(GenericBackgroundSize::Explicit { width, height });
|
||||||
}
|
}
|
||||||
let location = input.current_source_location();
|
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||||
let ident = input.expect_ident()?;
|
"cover" => GenericBackgroundSize::Cover,
|
||||||
(match_ignore_ascii_case! { &ident,
|
"contain" => GenericBackgroundSize::Contain,
|
||||||
"cover" => Ok(GenericBackgroundSize::Cover),
|
|
||||||
"contain" => Ok(GenericBackgroundSize::Contain),
|
|
||||||
_ => Err(()),
|
|
||||||
}).map_err(|()| {
|
|
||||||
location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,8 +36,8 @@ impl BackgroundSize {
|
||||||
/// Returns `auto auto`.
|
/// Returns `auto auto`.
|
||||||
pub fn auto() -> Self {
|
pub fn auto() -> Self {
|
||||||
GenericBackgroundSize::Explicit {
|
GenericBackgroundSize::Explicit {
|
||||||
width: LengthOrPercentageOrAuto::Auto,
|
width: NonNegativeLengthOrPercentageOrAuto::auto(),
|
||||||
height: LengthOrPercentageOrAuto::Auto,
|
height: NonNegativeLengthOrPercentageOrAuto::auto(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpa
|
||||||
pub use self::time::Time;
|
pub use self::time::Time;
|
||||||
pub use self::transform::{Rotate, Scale, TimingFunction, Transform};
|
pub use self::transform::{Rotate, Scale, TimingFunction, Transform};
|
||||||
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
|
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
|
||||||
pub use self::ui::{CaretColor, Cursor, MozForceBrokenImageIcon};
|
pub use self::ui::{ColorOrAuto, Cursor, MozForceBrokenImageIcon};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use self::ui::CursorImage;
|
pub use self::ui::CursorImage;
|
||||||
pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
|
pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
|
||||||
|
|
|
@ -9,25 +9,14 @@ use parser::{Parse, ParserContext};
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
|
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
|
||||||
use style_traits::cursor::CursorKind;
|
use style_traits::cursor::CursorKind;
|
||||||
|
use values::{Auto, Either};
|
||||||
use values::generics::ui as generics;
|
use values::generics::ui as generics;
|
||||||
use values::specified::Number;
|
use values::specified::Number;
|
||||||
use values::specified::color::Color;
|
use values::specified::color::Color;
|
||||||
use values::specified::url::SpecifiedImageUrl;
|
use values::specified::url::SpecifiedImageUrl;
|
||||||
|
|
||||||
/// A specified value for the `caret-color` property.
|
/// auto | <color>
|
||||||
pub type CaretColor = generics::CaretColor<Color>;
|
pub type ColorOrAuto = Either<Color, Auto>;
|
||||||
|
|
||||||
impl Parse for CaretColor {
|
|
||||||
fn parse<'i, 't>(
|
|
||||||
context: &ParserContext,
|
|
||||||
input: &mut Parser<'i, 't>,
|
|
||||||
) -> Result<Self, ParseError<'i>> {
|
|
||||||
if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
|
|
||||||
return Ok(generics::CaretColor::Auto);
|
|
||||||
}
|
|
||||||
Ok(generics::CaretColor::Color(Color::parse(context, input)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A specified value for the `cursor` property.
|
/// A specified value for the `cursor` property.
|
||||||
pub type Cursor = generics::Cursor<CursorImage>;
|
pub type Cursor = generics::Cursor<CursorImage>;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue