mirror of
https://github.com/servo/servo.git
synced 2025-07-08 16:03:40 +01:00
Auto merge of #15463 - Manishearth:buncha-props, r=mbrubeck
stylo: Implement a bunch of properties r? @mbrubeck or @heycam <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15463) <!-- Reviewable:end -->
This commit is contained in:
commit
e985ad5422
20 changed files with 451 additions and 246 deletions
|
@ -1176,10 +1176,11 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
fn adjust_clip_for_style(&self,
|
fn adjust_clip_for_style(&self,
|
||||||
parent_clip: &mut ClippingRegion,
|
parent_clip: &mut ClippingRegion,
|
||||||
stacking_relative_border_box: &Rect<Au>) {
|
stacking_relative_border_box: &Rect<Au>) {
|
||||||
|
use style::values::Either;
|
||||||
// Account for `clip` per CSS 2.1 § 11.1.2.
|
// Account for `clip` per CSS 2.1 § 11.1.2.
|
||||||
let style_clip_rect = match (self.style().get_box().position,
|
let style_clip_rect = match (self.style().get_box().position,
|
||||||
self.style().get_effects().clip.0) {
|
self.style().get_effects().clip) {
|
||||||
(position::T::absolute, Some(style_clip_rect)) => style_clip_rect,
|
(position::T::absolute, Either::First(style_clip_rect)) => style_clip_rect,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -93,4 +93,13 @@ impl<T> nsTArray<T> {
|
||||||
let mut header = self.header_mut();
|
let mut header = self.header_mut();
|
||||||
header.mLength = len;
|
header.mLength = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resizes an array containing only POD elements
|
||||||
|
///
|
||||||
|
/// This will not leak since it only works on POD types (and thus doesn't assert)
|
||||||
|
pub unsafe fn set_len_pod(&mut self, len: u32) where T: Copy {
|
||||||
|
self.ensure_capacity(len as usize);
|
||||||
|
let mut header = unsafe { self.header_mut() };
|
||||||
|
header.mLength = len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,6 +328,39 @@ def set_gecko_property(ffi_name, expr):
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
<%def name="impl_absolute_length(ident, gecko_ffi_name, need_clone=False)">
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
|
||||||
|
${set_gecko_property(gecko_ffi_name, "v.0")}
|
||||||
|
}
|
||||||
|
<%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
|
||||||
|
% if need_clone:
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
|
||||||
|
Au(self.gecko.${gecko_ffi_name})
|
||||||
|
}
|
||||||
|
% endif
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="impl_position(ident, gecko_ffi_name, need_clone=False)">
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
|
||||||
|
${set_gecko_property("%s.mXPosition" % gecko_ffi_name, "v.horizontal.into()")}
|
||||||
|
${set_gecko_property("%s.mYPosition" % gecko_ffi_name, "v.vertical.into()")}
|
||||||
|
}
|
||||||
|
<%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
|
||||||
|
% if need_clone:
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
|
||||||
|
use values::computed::Position;
|
||||||
|
Position {
|
||||||
|
horizontal: self.gecko.${gecko_ffi_name}.mXPosition.into(),
|
||||||
|
vertical: self.gecko.${gecko_ffi_name}.mYPosition.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
% endif
|
||||||
|
</%def>
|
||||||
|
|
||||||
<%def name="impl_color(ident, gecko_ffi_name, need_clone=False, complex_color=True)">
|
<%def name="impl_color(ident, gecko_ffi_name, need_clone=False, complex_color=True)">
|
||||||
<%call expr="impl_color_setter(ident, gecko_ffi_name, complex_color)"></%call>
|
<%call expr="impl_color_setter(ident, gecko_ffi_name, complex_color)"></%call>
|
||||||
<%call expr="impl_color_copy(ident, gecko_ffi_name, complex_color)"></%call>
|
<%call expr="impl_color_copy(ident, gecko_ffi_name, complex_color)"></%call>
|
||||||
|
@ -501,7 +534,8 @@ impl Debug 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 = {
|
||||||
"length::LengthOrAuto": impl_style_coord,
|
"length::LengthOrAuto": impl_style_coord,
|
||||||
"Length": impl_style_coord,
|
"Length": impl_absolute_length,
|
||||||
|
"Position": impl_position,
|
||||||
"LengthOrPercentage": impl_style_coord,
|
"LengthOrPercentage": impl_style_coord,
|
||||||
"LengthOrPercentageOrAuto": impl_style_coord,
|
"LengthOrPercentageOrAuto": impl_style_coord,
|
||||||
"LengthOrPercentageOrNone": impl_style_coord,
|
"LengthOrPercentageOrNone": impl_style_coord,
|
||||||
|
@ -1169,7 +1203,8 @@ fn static_assert() {
|
||||||
animation-iteration-count animation-timing-function
|
animation-iteration-count animation-timing-function
|
||||||
-moz-binding page-break-before page-break-after
|
-moz-binding page-break-before page-break-after
|
||||||
scroll-snap-points-x scroll-snap-points-y transform
|
scroll-snap-points-x scroll-snap-points-y transform
|
||||||
scroll-snap-type-y perspective-origin transform-origin""" %>
|
scroll-snap-type-y scroll-snap-coordinate
|
||||||
|
perspective-origin transform-origin""" %>
|
||||||
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
|
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
|
||||||
|
|
||||||
// We manually-implement the |display| property until we get general
|
// We manually-implement the |display| property until we get general
|
||||||
|
@ -1340,6 +1375,34 @@ fn static_assert() {
|
||||||
|
|
||||||
${impl_coord_copy('scroll_snap_points_y', 'mScrollSnapPointsY')}
|
${impl_coord_copy('scroll_snap_points_y', 'mScrollSnapPointsY')}
|
||||||
|
|
||||||
|
pub fn set_scroll_snap_coordinate(&mut self, v: longhands::scroll_snap_coordinate::computed_value::T) {
|
||||||
|
unsafe { self.gecko.mScrollSnapCoordinate.set_len_pod(v.0.len() as u32); }
|
||||||
|
for (gecko, servo) in self.gecko.mScrollSnapCoordinate
|
||||||
|
.iter_mut()
|
||||||
|
.zip(v.0.iter()) {
|
||||||
|
gecko.mXPosition = servo.horizontal.into();
|
||||||
|
gecko.mYPosition = servo.vertical.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_scroll_snap_coordinate_from(&mut self, other: &Self) {
|
||||||
|
unsafe {
|
||||||
|
self.gecko.mScrollSnapCoordinate
|
||||||
|
.set_len_pod(other.gecko.mScrollSnapCoordinate.len() as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (this, that) in self.gecko.mScrollSnapCoordinate
|
||||||
|
.iter_mut()
|
||||||
|
.zip(other.gecko.mScrollSnapCoordinate.iter()) {
|
||||||
|
*this = *that;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
longhands::scroll_snap_coordinate::computed_value::T(vec)
|
||||||
|
}
|
||||||
|
|
||||||
<%def name="transform_function_arm(name, keyword, items)">
|
<%def name="transform_function_arm(name, keyword, items)">
|
||||||
<%
|
<%
|
||||||
pattern = None
|
pattern = None
|
||||||
|
@ -1971,7 +2034,7 @@ fn static_assert() {
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="List"
|
<%self:impl_trait style_struct_name="List"
|
||||||
skip_longhands="list-style-image list-style-type quotes"
|
skip_longhands="list-style-image list-style-type quotes -moz-image-region"
|
||||||
skip_additionals="*">
|
skip_additionals="*">
|
||||||
|
|
||||||
pub fn set_list_style_image(&mut self, image: longhands::list_style_image::computed_value::T) {
|
pub fn set_list_style_image(&mut self, image: longhands::list_style_image::computed_value::T) {
|
||||||
|
@ -2037,6 +2100,28 @@ fn static_assert() {
|
||||||
unsafe { self.gecko.mQuotes.set(&other.gecko.mQuotes); }
|
unsafe { self.gecko.mQuotes.set(&other.gecko.mQuotes); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn set__moz_image_region(&mut self, v: longhands::_moz_image_region::computed_value::T) {
|
||||||
|
use values::Either;
|
||||||
|
|
||||||
|
match v {
|
||||||
|
Either::Second(_auto) => {
|
||||||
|
self.gecko.mImageRegion.x = 0;
|
||||||
|
self.gecko.mImageRegion.y = 0;
|
||||||
|
self.gecko.mImageRegion.width = 0;
|
||||||
|
self.gecko.mImageRegion.height = 0;
|
||||||
|
}
|
||||||
|
Either::First(rect) => {
|
||||||
|
self.gecko.mImageRegion.x = rect.left.0;
|
||||||
|
self.gecko.mImageRegion.y = rect.top.0;
|
||||||
|
self.gecko.mImageRegion.height = rect.bottom.unwrap_or(Au(0)).0 - self.gecko.mImageRegion.y;
|
||||||
|
self.gecko.mImageRegion.width = rect.right.unwrap_or(Au(0)).0 - self.gecko.mImageRegion.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${impl_simple_copy('_moz_image_region', 'mImageRegion')}
|
||||||
|
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="Effects"
|
<%self:impl_trait style_struct_name="Effects"
|
||||||
|
@ -2204,7 +2289,7 @@ fn static_assert() {
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="InheritedText"
|
<%self:impl_trait style_struct_name="InheritedText"
|
||||||
skip_longhands="text-align text-emphasis-style text-shadow line-height letter-spacing word-spacing
|
skip_longhands="text-align text-emphasis-style text-shadow line-height letter-spacing word-spacing
|
||||||
-webkit-text-stroke-width">
|
-webkit-text-stroke-width text-emphasis-position -moz-tab-size">
|
||||||
|
|
||||||
<% text_align_keyword = Keyword("text-align", "start end left right center justify -moz-center -moz-left " +
|
<% text_align_keyword = Keyword("text-align", "start end left right center justify -moz-center -moz-left " +
|
||||||
"-moz-right match-parent") %>
|
"-moz-right match-parent") %>
|
||||||
|
@ -2310,6 +2395,26 @@ fn static_assert() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_text_emphasis_position(&mut self, v: longhands::text_emphasis_position::computed_value::T) {
|
||||||
|
use properties::longhands::text_emphasis_position::*;
|
||||||
|
|
||||||
|
let mut result = match v.0 {
|
||||||
|
HorizontalWritingModeValue::Over => structs::NS_STYLE_TEXT_EMPHASIS_POSITION_OVER as u8,
|
||||||
|
HorizontalWritingModeValue::Under => structs::NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER as u8,
|
||||||
|
};
|
||||||
|
match v.1 {
|
||||||
|
VerticalWritingModeValue::Right => {
|
||||||
|
result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT as u8;
|
||||||
|
}
|
||||||
|
VerticalWritingModeValue::Left => {
|
||||||
|
result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT as u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.gecko.mTextEmphasisPosition = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
<%call expr="impl_simple_copy('text_emphasis_position', 'mTextEmphasisPosition')"></%call>
|
||||||
|
|
||||||
pub fn set_text_emphasis_style(&mut self, v: longhands::text_emphasis_style::computed_value::T) {
|
pub fn set_text_emphasis_style(&mut self, v: longhands::text_emphasis_style::computed_value::T) {
|
||||||
use nsstring::nsCString;
|
use nsstring::nsCString;
|
||||||
use properties::longhands::text_emphasis_style::computed_value::T;
|
use properties::longhands::text_emphasis_style::computed_value::T;
|
||||||
|
@ -2353,6 +2458,22 @@ fn static_assert() {
|
||||||
|
|
||||||
<%call expr="impl_app_units('_webkit_text_stroke_width', 'mWebkitTextStrokeWidth', need_clone=False)"></%call>
|
<%call expr="impl_app_units('_webkit_text_stroke_width', 'mWebkitTextStrokeWidth', need_clone=False)"></%call>
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn set__moz_tab_size(&mut self, v: longhands::_moz_tab_size::computed_value::T) {
|
||||||
|
use values::Either;
|
||||||
|
|
||||||
|
match v {
|
||||||
|
Either::Second(number) => {
|
||||||
|
self.gecko.mTabSize.set_value(CoordDataValue::Factor(number));
|
||||||
|
}
|
||||||
|
Either::First(au) => {
|
||||||
|
self.gecko.mTabSize.set(au);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<%call expr="impl_coord_copy('_moz_tab_size', 'mTabSize')"></%call>
|
||||||
|
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
<%self:impl_trait style_struct_name="Text"
|
<%self:impl_trait style_struct_name="Text"
|
||||||
|
@ -2815,6 +2936,18 @@ clip-path
|
||||||
}
|
}
|
||||||
</%self:impl_trait>
|
</%self:impl_trait>
|
||||||
|
|
||||||
|
<%self:impl_trait style_struct_name="XUL"
|
||||||
|
skip_longhands="-moz-stack-sizing">
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn set__moz_stack_sizing(&mut self, v: longhands::_moz_stack_sizing::computed_value::T) {
|
||||||
|
use properties::longhands::_moz_stack_sizing::computed_value::T;
|
||||||
|
self.gecko.mStretchStack = v == T::stretch_to_fit;
|
||||||
|
}
|
||||||
|
|
||||||
|
${impl_simple_copy('_moz_stack_sizing', 'mStretchStack')}
|
||||||
|
</%self:impl_trait>
|
||||||
|
|
||||||
<%def name="define_ffi_struct_accessor(style_struct)">
|
<%def name="define_ffi_struct_accessor(style_struct)">
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(non_snake_case, unused_variables)]
|
#[allow(non_snake_case, unused_variables)]
|
||||||
|
|
|
@ -21,8 +21,9 @@
|
||||||
</%call>
|
</%call>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="predefined_type(name, type, initial_value, parse_method='parse', needs_context=True, **kwargs)">
|
<%def name="predefined_type(name, type, initial_value, parse_method='parse',
|
||||||
<%call expr="longhand(name, predefined_type=type, **kwargs)">
|
needs_context=True, vector=False, **kwargs)">
|
||||||
|
<%def name="predefined_type_inner(name, type, initial_value, parse_method)">
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use cssparser::{Color as CSSParserColor, RGBA};
|
use cssparser::{Color as CSSParserColor, RGBA};
|
||||||
|
@ -40,7 +41,16 @@
|
||||||
specified::${type}::${parse_method}(input)
|
specified::${type}::${parse_method}(input)
|
||||||
% endif
|
% endif
|
||||||
}
|
}
|
||||||
|
</%def>
|
||||||
|
% if vector:
|
||||||
|
<%call expr="vector_longhand(name, predefined_type=type, **kwargs)">
|
||||||
|
${predefined_type_inner(name, type, initial_value, parse_method)}
|
||||||
</%call>
|
</%call>
|
||||||
|
% else:
|
||||||
|
<%call expr="longhand(name, predefined_type=type, **kwargs)">
|
||||||
|
${predefined_type_inner(name, type, initial_value, parse_method)}
|
||||||
|
</%call>
|
||||||
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
// FIXME (Manishearth): Add computed_value_as_specified argument
|
// FIXME (Manishearth): Add computed_value_as_specified argument
|
||||||
|
@ -56,7 +66,7 @@
|
||||||
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, gecko_only=False, allow_empty=False, **kwargs)">
|
<%def name="vector_longhand(name, gecko_only=False, allow_empty=False, delegate_animate=False, **kwargs)">
|
||||||
<%call expr="longhand(name, **kwargs)">
|
<%call expr="longhand(name, **kwargs)">
|
||||||
% if not gecko_only:
|
% if not gecko_only:
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -87,6 +97,15 @@
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct T(pub Vec<single_value::T>);
|
pub struct T(pub Vec<single_value::T>);
|
||||||
|
|
||||||
|
% if delegate_animate:
|
||||||
|
use properties::animated_properties::Interpolate;
|
||||||
|
impl Interpolate for T {
|
||||||
|
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
||||||
|
self.0.interpolate(&other.0, progress).map(T)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
% endif
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for computed_value::T {
|
impl ToCss for computed_value::T {
|
||||||
|
|
|
@ -10,8 +10,6 @@ use euclid::{Point2D, Size2D};
|
||||||
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID;
|
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID;
|
||||||
use properties::{DeclaredValue, PropertyDeclaration};
|
use properties::{DeclaredValue, PropertyDeclaration};
|
||||||
use properties::longhands;
|
use properties::longhands;
|
||||||
use properties::longhands::background_position_x::computed_value::T as BackgroundPositionX;
|
|
||||||
use properties::longhands::background_position_y::computed_value::T as BackgroundPositionY;
|
|
||||||
use properties::longhands::background_size::computed_value::T as BackgroundSize;
|
use properties::longhands::background_size::computed_value::T as BackgroundSize;
|
||||||
use properties::longhands::font_weight::computed_value::T as FontWeight;
|
use properties::longhands::font_weight::computed_value::T as FontWeight;
|
||||||
use properties::longhands::line_height::computed_value::T as LineHeight;
|
use properties::longhands::line_height::computed_value::T as LineHeight;
|
||||||
|
@ -33,7 +31,7 @@ use super::ComputedValues;
|
||||||
use values::CSSFloat;
|
use values::CSSFloat;
|
||||||
use values::Either;
|
use values::Either;
|
||||||
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
|
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
|
||||||
use values::computed::{BorderRadiusSize, LengthOrNone};
|
use values::computed::{BorderRadiusSize, ClipRect, LengthOrNone};
|
||||||
use values::computed::{CalcLengthOrPercentage, Context, LengthOrPercentage};
|
use values::computed::{CalcLengthOrPercentage, Context, LengthOrPercentage};
|
||||||
use values::computed::position::{HorizontalPosition, Position, VerticalPosition};
|
use values::computed::position::{HorizontalPosition, Position, VerticalPosition};
|
||||||
use values::computed::ToComputedValue;
|
use values::computed::ToComputedValue;
|
||||||
|
@ -724,17 +722,16 @@ impl Interpolate for VerticalPosition {
|
||||||
|
|
||||||
impl RepeatableListInterpolate for VerticalPosition {}
|
impl RepeatableListInterpolate for VerticalPosition {}
|
||||||
|
|
||||||
impl Interpolate for BackgroundPositionX {
|
/// https://drafts.csswg.org/css-transitions/#animtype-rect
|
||||||
|
impl Interpolate for ClipRect {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
|
||||||
Ok(BackgroundPositionX(try!(self.0.interpolate(&other.0, progress))))
|
Ok(ClipRect {
|
||||||
}
|
top: try!(self.top.interpolate(&other.top, time)),
|
||||||
}
|
right: try!(self.right.interpolate(&other.right, time)),
|
||||||
|
bottom: try!(self.bottom.interpolate(&other.bottom, time)),
|
||||||
impl Interpolate for BackgroundPositionY {
|
left: try!(self.left.interpolate(&other.left, time)),
|
||||||
#[inline]
|
})
|
||||||
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
|
||||||
Ok(BackgroundPositionY(try!(self.0.interpolate(&other.0, progress))))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,8 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
||||||
</%helpers:vector_longhand>
|
</%helpers:vector_longhand>
|
||||||
|
|
||||||
<%helpers:vector_longhand name="background-position-x" animatable="True"
|
<%helpers:vector_longhand name="background-position-x" animatable="True"
|
||||||
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x">
|
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x"
|
||||||
|
delegate_animate="True">
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use values::HasViewportPercentage;
|
use values::HasViewportPercentage;
|
||||||
|
@ -139,7 +140,8 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
||||||
</%helpers:vector_longhand>
|
</%helpers:vector_longhand>
|
||||||
|
|
||||||
<%helpers:vector_longhand name="background-position-y" animatable="True"
|
<%helpers:vector_longhand name="background-position-y" animatable="True"
|
||||||
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-y">
|
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-y"
|
||||||
|
delegate_animate="True">
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use values::HasViewportPercentage;
|
use values::HasViewportPercentage;
|
||||||
|
|
|
@ -257,10 +257,10 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
||||||
let mut values = vec![];
|
let mut values = vec![];
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
let value = input.try(|input| LengthOrNumber::parse_non_negative(input));
|
let value = input.try(|input| LengthOrNumber::parse_non_negative(context, input));
|
||||||
match value {
|
match value {
|
||||||
Ok(val) => values.push(val),
|
Ok(val) => values.push(val),
|
||||||
Err(_) => break,
|
Err(_) => break,
|
||||||
|
|
|
@ -1049,6 +1049,25 @@ ${helpers.single_keyword("animation-fill-mode",
|
||||||
</%helpers:longhand>
|
</%helpers:longhand>
|
||||||
|
|
||||||
|
|
||||||
|
${helpers.predefined_type("scroll-snap-destination",
|
||||||
|
"Position",
|
||||||
|
"computed::Position::zero()",
|
||||||
|
products="gecko",
|
||||||
|
boxed="True",
|
||||||
|
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)",
|
||||||
|
animatable=True)}
|
||||||
|
|
||||||
|
${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
|
"Position",
|
||||||
|
"computed::Position::zero()",
|
||||||
|
vector=True,
|
||||||
|
products="gecko",
|
||||||
|
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)",
|
||||||
|
animatable=True,
|
||||||
|
allow_empty=True,
|
||||||
|
delegate_animate=True)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<%helpers:longhand name="transform" products="gecko servo" extra_prefixes="webkit"
|
<%helpers:longhand name="transform" products="gecko servo" extra_prefixes="webkit"
|
||||||
animatable="True"
|
animatable="True"
|
||||||
|
|
|
@ -77,217 +77,13 @@ ${helpers.predefined_type("opacity",
|
||||||
</%helpers:vector_longhand>
|
</%helpers:vector_longhand>
|
||||||
|
|
||||||
// FIXME: This prop should be animatable
|
// FIXME: This prop should be animatable
|
||||||
<%helpers:longhand name="clip" products="servo" animatable="False" boxed="True"
|
${helpers.predefined_type("clip",
|
||||||
spec="https://drafts.fxtf.org/css-masking/#clip-property">
|
"ClipRectOrAuto",
|
||||||
use std::fmt;
|
"computed::ClipRectOrAuto::auto()",
|
||||||
use style_traits::ToCss;
|
animatable=False,
|
||||||
use values::HasViewportPercentage;
|
products="servo",
|
||||||
|
boxed="True",
|
||||||
// NB: `top` and `left` are 0 if `auto` per CSS 2.1 11.1.2.
|
spec="https://drafts.fxtf.org/css-masking/#clip-property")}
|
||||||
|
|
||||||
pub mod computed_value {
|
|
||||||
use app_units::Au;
|
|
||||||
use properties::animated_properties::Interpolate;
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
pub struct ClipRect {
|
|
||||||
pub top: Au,
|
|
||||||
pub right: Option<Au>,
|
|
||||||
pub bottom: Option<Au>,
|
|
||||||
pub left: Au,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
pub struct T(pub Option<ClipRect>);
|
|
||||||
|
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-transitions/#animtype-rect
|
|
||||||
impl Interpolate for ClipRect {
|
|
||||||
#[inline]
|
|
||||||
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
|
|
||||||
Ok(ClipRect {
|
|
||||||
top: try!(self.top.interpolate(&other.top, time)),
|
|
||||||
right: try!(self.right.interpolate(&other.right, time)),
|
|
||||||
bottom: try!(self.bottom.interpolate(&other.bottom, time)),
|
|
||||||
left: try!(self.left.interpolate(&other.left, time)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for computed_value::T {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
match self.0 {
|
|
||||||
None => dest.write_str("auto"),
|
|
||||||
Some(rect) => {
|
|
||||||
try!(dest.write_str("rect("));
|
|
||||||
try!(rect.top.to_css(dest));
|
|
||||||
try!(dest.write_str(", "));
|
|
||||||
if let Some(right) = rect.right {
|
|
||||||
try!(right.to_css(dest));
|
|
||||||
try!(dest.write_str(", "));
|
|
||||||
} else {
|
|
||||||
try!(dest.write_str("auto, "));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(bottom) = rect.bottom {
|
|
||||||
try!(bottom.to_css(dest));
|
|
||||||
try!(dest.write_str(", "));
|
|
||||||
} else {
|
|
||||||
try!(dest.write_str("auto, "));
|
|
||||||
}
|
|
||||||
|
|
||||||
try!(rect.left.to_css(dest));
|
|
||||||
try!(dest.write_str(")"));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasViewportPercentage for SpecifiedClipRect {
|
|
||||||
fn has_viewport_percentage(&self) -> bool {
|
|
||||||
self.top.has_viewport_percentage() ||
|
|
||||||
self.right.as_ref().map_or(false, |x| x.has_viewport_percentage()) ||
|
|
||||||
self.bottom.as_ref().map_or(false, |x| x.has_viewport_percentage()) ||
|
|
||||||
self.left.has_viewport_percentage()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
pub struct SpecifiedClipRect {
|
|
||||||
pub top: specified::Length,
|
|
||||||
pub right: Option<specified::Length>,
|
|
||||||
pub bottom: Option<specified::Length>,
|
|
||||||
pub left: specified::Length,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasViewportPercentage for SpecifiedValue {
|
|
||||||
fn has_viewport_percentage(&self) -> bool {
|
|
||||||
self.0.as_ref().map_or(false, |x| x.has_viewport_percentage())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
pub struct SpecifiedValue(Option<SpecifiedClipRect>);
|
|
||||||
|
|
||||||
impl ToCss for SpecifiedClipRect {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
try!(dest.write_str("rect("));
|
|
||||||
|
|
||||||
try!(self.top.to_css(dest));
|
|
||||||
try!(dest.write_str(", "));
|
|
||||||
|
|
||||||
if let Some(ref right) = self.right {
|
|
||||||
try!(right.to_css(dest));
|
|
||||||
try!(dest.write_str(", "));
|
|
||||||
} else {
|
|
||||||
try!(dest.write_str("auto, "));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ref bottom) = self.bottom {
|
|
||||||
try!(bottom.to_css(dest));
|
|
||||||
try!(dest.write_str(", "));
|
|
||||||
} else {
|
|
||||||
try!(dest.write_str("auto, "));
|
|
||||||
}
|
|
||||||
|
|
||||||
try!(self.left.to_css(dest));
|
|
||||||
|
|
||||||
try!(dest.write_str(")"));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for SpecifiedValue {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
if let Some(ref rect) = self.0 {
|
|
||||||
rect.to_css(dest)
|
|
||||||
} else {
|
|
||||||
dest.write_str("auto")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
|
||||||
computed_value::T(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for SpecifiedValue {
|
|
||||||
type ComputedValue = computed_value::T;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
|
||||||
computed_value::T(self.0.as_ref().map(|value| computed_value::ClipRect {
|
|
||||||
top: value.top.to_computed_value(context),
|
|
||||||
right: value.right.as_ref().map(|right| right.to_computed_value(context)),
|
|
||||||
bottom: value.bottom.as_ref().map(|bottom| bottom.to_computed_value(context)),
|
|
||||||
left: value.left.to_computed_value(context),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &computed_value::T) -> Self {
|
|
||||||
SpecifiedValue(computed.0.map(|value| SpecifiedClipRect {
|
|
||||||
top: ToComputedValue::from_computed_value(&value.top),
|
|
||||||
right: value.right.map(|right| ToComputedValue::from_computed_value(&right)),
|
|
||||||
bottom: value.bottom.map(|bottom| ToComputedValue::from_computed_value(&bottom)),
|
|
||||||
left: ToComputedValue::from_computed_value(&value.left),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
|
||||||
use app_units::Au;
|
|
||||||
use std::ascii::AsciiExt;
|
|
||||||
use values::specified::Length;
|
|
||||||
|
|
||||||
fn parse_argument(context: &ParserContext, input: &mut Parser) -> Result<Option<Length>, ()> {
|
|
||||||
if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
Length::parse(context, input).map(Some)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
|
|
||||||
return Ok(SpecifiedValue(None))
|
|
||||||
}
|
|
||||||
if !try!(input.expect_function()).eq_ignore_ascii_case("rect") {
|
|
||||||
return Err(())
|
|
||||||
}
|
|
||||||
|
|
||||||
input.parse_nested_block(|input| {
|
|
||||||
let top = try!(parse_argument(context, input));
|
|
||||||
let right;
|
|
||||||
let bottom;
|
|
||||||
let left;
|
|
||||||
|
|
||||||
if input.try(|input| input.expect_comma()).is_ok() {
|
|
||||||
right = try!(parse_argument(context, input));
|
|
||||||
try!(input.expect_comma());
|
|
||||||
bottom = try!(parse_argument(context, input));
|
|
||||||
try!(input.expect_comma());
|
|
||||||
left = try!(parse_argument(context, input));
|
|
||||||
} else {
|
|
||||||
right = try!(parse_argument(context, input));
|
|
||||||
bottom = try!(parse_argument(context, input));
|
|
||||||
left = try!(parse_argument(context, input));
|
|
||||||
}
|
|
||||||
Ok(SpecifiedValue(Some(SpecifiedClipRect {
|
|
||||||
top: top.unwrap_or(Length::zero()),
|
|
||||||
right: right,
|
|
||||||
bottom: bottom,
|
|
||||||
left: left.unwrap_or(Length::zero()),
|
|
||||||
})))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</%helpers:longhand>
|
|
||||||
|
|
||||||
// FIXME: This prop should be animatable
|
// FIXME: This prop should be animatable
|
||||||
<%helpers:longhand name="filter" animatable="False" extra_prefixes="webkit"
|
<%helpers:longhand name="filter" animatable="False" extra_prefixes="webkit"
|
||||||
|
|
|
@ -973,7 +973,7 @@ ${helpers.single_keyword("text-align-last",
|
||||||
}
|
}
|
||||||
</%helpers:longhand>
|
</%helpers:longhand>
|
||||||
|
|
||||||
<%helpers:longhand name="text-emphasis-position" animatable="False" products="none"
|
<%helpers:longhand name="text-emphasis-position" animatable="False" products="gecko"
|
||||||
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position">
|
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position">
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use values::computed::ComputedValueAsSpecified;
|
use values::computed::ComputedValueAsSpecified;
|
||||||
|
@ -1030,6 +1030,15 @@ ${helpers.predefined_type("text-emphasis-color", "CSSColor",
|
||||||
boxed=True,
|
boxed=True,
|
||||||
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color")}
|
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color")}
|
||||||
|
|
||||||
|
|
||||||
|
${helpers.predefined_type(
|
||||||
|
"-moz-tab-size", "LengthOrNumber",
|
||||||
|
"::values::Either::Second(8.0)",
|
||||||
|
"parse_non_negative",
|
||||||
|
products="gecko", animatable=False,
|
||||||
|
spec="https://drafts.csswg.org/css-text-3/#tab-size-property")}
|
||||||
|
|
||||||
|
|
||||||
// CSS Compatibility
|
// CSS Compatibility
|
||||||
// https://compat.spec.whatwg.org
|
// https://compat.spec.whatwg.org
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
|
@ -1070,6 +1079,7 @@ ${helpers.predefined_type(
|
||||||
}
|
}
|
||||||
</%helpers:longhand>
|
</%helpers:longhand>
|
||||||
|
|
||||||
|
|
||||||
// CSS Ruby Layout Module Level 1
|
// CSS Ruby Layout Module Level 1
|
||||||
// https://drafts.csswg.org/css-ruby/
|
// https://drafts.csswg.org/css-ruby/
|
||||||
${helpers.single_keyword("ruby-align", "start center space-between space-around",
|
${helpers.single_keyword("ruby-align", "start center space-between space-around",
|
||||||
|
|
|
@ -101,3 +101,11 @@ ${helpers.predefined_type("list-style-image", "UrlOrNone", "Either::Second(None_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</%helpers:longhand>
|
</%helpers:longhand>
|
||||||
|
|
||||||
|
${helpers.predefined_type("-moz-image-region",
|
||||||
|
"ClipRectOrAuto",
|
||||||
|
"computed::ClipRectOrAuto::auto()",
|
||||||
|
animatable=False,
|
||||||
|
products="gecko",
|
||||||
|
boxed="True",
|
||||||
|
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)")}
|
||||||
|
|
|
@ -114,5 +114,5 @@ ${helpers.predefined_type("outline-color", "CSSColor", "::cssparser::Color::Curr
|
||||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)")}
|
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)")}
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
${helpers.predefined_type("outline-offset", "Length", "Au(0)", products="servo", animatable=True,
|
${helpers.predefined_type("outline-offset", "Length", "Au(0)", products="servo gecko", animatable=True,
|
||||||
spec="https://drafts.csswg.org/css-ui/#propdef-outline-offset")}
|
spec="https://drafts.csswg.org/css-ui/#propdef-outline-offset")}
|
||||||
|
|
|
@ -210,6 +210,14 @@ ${helpers.single_keyword("object-fit", "fill contain cover none scale-down",
|
||||||
products="gecko", animatable=False,
|
products="gecko", animatable=False,
|
||||||
spec="https://drafts.csswg.org/css-images/#propdef-object-fit")}
|
spec="https://drafts.csswg.org/css-images/#propdef-object-fit")}
|
||||||
|
|
||||||
|
${helpers.predefined_type("object-position",
|
||||||
|
"Position",
|
||||||
|
"computed::Position::zero()",
|
||||||
|
products="gecko",
|
||||||
|
boxed="True",
|
||||||
|
spec="https://drafts.csswg.org/css-images-3/#the-object-position",
|
||||||
|
animatable=True)}
|
||||||
|
|
||||||
<% grid_longhands = ["grid-row-start", "grid-row-end", "grid-column-start", "grid-column-end"] %>
|
<% grid_longhands = ["grid-row-start", "grid-row-end", "grid-column-start", "grid-column-end"] %>
|
||||||
|
|
||||||
% for longhand in grid_longhands:
|
% for longhand in grid_longhands:
|
||||||
|
|
|
@ -23,3 +23,9 @@ ${helpers.single_keyword("-moz-user-select", "auto text none all", products="gec
|
||||||
gecko_inexhaustive=True,
|
gecko_inexhaustive=True,
|
||||||
animatable=False,
|
animatable=False,
|
||||||
spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select")}
|
spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select")}
|
||||||
|
|
||||||
|
${helpers.single_keyword("-moz-window-dragging", "default drag no-drag", products="gecko",
|
||||||
|
gecko_ffi_name="mWindowDragging",
|
||||||
|
gecko_enum_prefix="StyleWindowDragging",
|
||||||
|
animatable=False,
|
||||||
|
spec="None (Nonstandard Firefox-only property)")}
|
||||||
|
|
|
@ -22,3 +22,10 @@ ${helpers.predefined_type("-moz-box-flex", "Number", "0.0", "parse_non_negative"
|
||||||
animatable=False,
|
animatable=False,
|
||||||
alias="-webkit-box-flex",
|
alias="-webkit-box-flex",
|
||||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-flex)")}
|
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-flex)")}
|
||||||
|
|
||||||
|
|
||||||
|
${helpers.single_keyword("-moz-stack-sizing", "stretch-to-fit ignore",
|
||||||
|
products="gecko", gecko_ffi_name="mStretchStack",
|
||||||
|
gecko_constant_prefix="NS_STYLE_STACK_SIZING",
|
||||||
|
animatable=False,
|
||||||
|
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-stack-sizing)")}
|
||||||
|
|
|
@ -1589,7 +1589,7 @@ impl ComputedValues {
|
||||||
// TODO(gw): Add clip-path, isolation, mask-image, mask-border-source when supported.
|
// TODO(gw): Add clip-path, isolation, mask-image, mask-border-source when supported.
|
||||||
if effects.opacity < 1.0 ||
|
if effects.opacity < 1.0 ||
|
||||||
!effects.filter.is_empty() ||
|
!effects.filter.is_empty() ||
|
||||||
effects.clip.0.is_some() {
|
!effects.clip.is_auto() {
|
||||||
effects.mix_blend_mode != mix_blend_mode::T::normal ||
|
effects.mix_blend_mode != mix_blend_mode::T::normal ||
|
||||||
return transform_style::T::flat;
|
return transform_style::T::flat;
|
||||||
}
|
}
|
||||||
|
@ -2290,10 +2290,10 @@ pub fn modify_style_for_text(style: &mut Arc<ComputedValues>) {
|
||||||
/// doesn't clip its children.
|
/// doesn't clip its children.
|
||||||
#[cfg(feature = "servo")]
|
#[cfg(feature = "servo")]
|
||||||
pub fn modify_style_for_inline_absolute_hypothetical_fragment(style: &mut Arc<ComputedValues>) {
|
pub fn modify_style_for_inline_absolute_hypothetical_fragment(style: &mut Arc<ComputedValues>) {
|
||||||
if style.get_effects().clip.0.is_some() {
|
if !style.get_effects().clip.is_auto() {
|
||||||
let mut style = Arc::make_mut(style);
|
let mut style = Arc::make_mut(style);
|
||||||
let effects_style = Arc::make_mut(&mut style.effects);
|
let effects_style = Arc::make_mut(&mut style.effects);
|
||||||
effects_style.clip.0 = None
|
effects_style.clip = Either::auto()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,12 @@ use super::{CSSFloat, specified};
|
||||||
pub use cssparser::Color as CSSColor;
|
pub use cssparser::Color as CSSColor;
|
||||||
pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image};
|
pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image};
|
||||||
pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
|
pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
|
||||||
pub use super::{Either, None_};
|
pub use super::{Auto, Either, None_};
|
||||||
pub use super::specified::{Angle, BorderStyle, GridLine, Time, UrlOrNone};
|
pub use super::specified::{Angle, BorderStyle, GridLine, Time, UrlOrNone};
|
||||||
pub use super::specified::url::UrlExtraData;
|
pub use super::specified::url::UrlExtraData;
|
||||||
pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone};
|
pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone};
|
||||||
|
pub use self::position::Position;
|
||||||
|
|
||||||
pub mod basic_shape;
|
pub mod basic_shape;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
|
@ -176,3 +177,57 @@ pub type Number = CSSFloat;
|
||||||
|
|
||||||
/// A type used for opacity.
|
/// A type used for opacity.
|
||||||
pub type Opacity = CSSFloat;
|
pub type Opacity = CSSFloat;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
/// A computed cliprect for clip and image-region
|
||||||
|
pub struct ClipRect {
|
||||||
|
pub top: Au,
|
||||||
|
pub right: Option<Au>,
|
||||||
|
pub bottom: Option<Au>,
|
||||||
|
pub left: Au,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for ClipRect {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
try!(dest.write_str("rect("));
|
||||||
|
try!(self.top.to_css(dest));
|
||||||
|
try!(dest.write_str(", "));
|
||||||
|
if let Some(right) = self.right {
|
||||||
|
try!(right.to_css(dest));
|
||||||
|
try!(dest.write_str(", "));
|
||||||
|
} else {
|
||||||
|
try!(dest.write_str("auto, "));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(bottom) = self.bottom {
|
||||||
|
try!(bottom.to_css(dest));
|
||||||
|
try!(dest.write_str(", "));
|
||||||
|
} else {
|
||||||
|
try!(dest.write_str("auto, "));
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(self.left.to_css(dest));
|
||||||
|
dest.write_str(")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// rect(...) | auto
|
||||||
|
pub type ClipRectOrAuto = Either<ClipRect, Auto>;
|
||||||
|
|
||||||
|
impl ClipRectOrAuto {
|
||||||
|
/// Return an auto (default for clip-rect and image-region) value
|
||||||
|
pub fn auto() -> Self {
|
||||||
|
Either::Second(Auto)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if it is auto
|
||||||
|
pub fn is_auto(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
Either::Second(_) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,16 @@ pub struct Position {
|
||||||
pub vertical: LengthOrPercentage,
|
pub vertical: LengthOrPercentage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Position {
|
||||||
|
/// Construct a position at (0, 0)
|
||||||
|
pub fn zero() -> Self {
|
||||||
|
Position {
|
||||||
|
horizontal: LengthOrPercentage::zero(),
|
||||||
|
vertical: LengthOrPercentage::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToCss for Position {
|
impl ToCss for Position {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
try!(self.horizontal.to_css(dest));
|
try!(self.horizontal.to_css(dest));
|
||||||
|
|
|
@ -1215,7 +1215,7 @@ pub type LengthOrNumber = Either<Length, Number>;
|
||||||
|
|
||||||
impl LengthOrNumber {
|
impl LengthOrNumber {
|
||||||
/// Parse a non-negative LengthOrNumber.
|
/// Parse a non-negative LengthOrNumber.
|
||||||
pub fn parse_non_negative(input: &mut Parser) -> Result<Self, ()> {
|
pub fn parse_non_negative(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
// We try to parse as a Number first because, for cases like LengthOrNumber,
|
// We try to parse as a Number first because, for cases like LengthOrNumber,
|
||||||
// we want "0" to be parsed as a plain Number rather than a Length (0px); this
|
// we want "0" to be parsed as a plain Number rather than a Length (0px); this
|
||||||
// matches the behaviour of all major browsers
|
// matches the behaviour of all major browsers
|
||||||
|
|
|
@ -16,7 +16,7 @@ use std::f32::consts::PI;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use super::{CSSFloat, HasViewportPercentage, Either, None_};
|
use super::{Auto, CSSFloat, HasViewportPercentage, Either, None_};
|
||||||
use super::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
|
use super::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
|
||||||
use super::computed::Shadow as ComputedShadow;
|
use super::computed::Shadow as ComputedShadow;
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ pub use self::image::{SizeKeyword, VerticalDirection};
|
||||||
pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage};
|
pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage};
|
||||||
pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength, CalcUnit};
|
pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength, CalcUnit};
|
||||||
|
pub use self::position::{HorizontalPosition, Position, VerticalPosition};
|
||||||
|
|
||||||
pub mod basic_shape;
|
pub mod basic_shape;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
|
@ -664,3 +665,127 @@ impl Shadow {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl HasViewportPercentage for ClipRect {
|
||||||
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
|
self.top.has_viewport_percentage() ||
|
||||||
|
self.right.as_ref().map_or(false, |x| x.has_viewport_percentage()) ||
|
||||||
|
self.bottom.as_ref().map_or(false, |x| x.has_viewport_percentage()) ||
|
||||||
|
self.left.has_viewport_percentage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
/// rect(<top>, <left>, <bottom>, <right>) used by clip and image-region
|
||||||
|
pub struct ClipRect {
|
||||||
|
/// <top> (<length> | <auto>). Auto maps to 0
|
||||||
|
pub top: Length,
|
||||||
|
/// <right> (<length> | <auto>)
|
||||||
|
pub right: Option<Length>,
|
||||||
|
/// <bottom> (<length> | <auto>)
|
||||||
|
pub bottom: Option<Length>,
|
||||||
|
/// <left> (<length> | <auto>). Auto maps to 0
|
||||||
|
pub left: Length,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl ToCss for ClipRect {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
try!(dest.write_str("rect("));
|
||||||
|
|
||||||
|
try!(self.top.to_css(dest));
|
||||||
|
try!(dest.write_str(", "));
|
||||||
|
|
||||||
|
if let Some(ref right) = self.right {
|
||||||
|
try!(right.to_css(dest));
|
||||||
|
try!(dest.write_str(", "));
|
||||||
|
} else {
|
||||||
|
try!(dest.write_str("auto, "));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref bottom) = self.bottom {
|
||||||
|
try!(bottom.to_css(dest));
|
||||||
|
try!(dest.write_str(", "));
|
||||||
|
} else {
|
||||||
|
try!(dest.write_str("auto, "));
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(self.left.to_css(dest));
|
||||||
|
|
||||||
|
try!(dest.write_str(")"));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToComputedValue for ClipRect {
|
||||||
|
type ComputedValue = super::computed::ClipRect;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, context: &Context) -> super::computed::ClipRect {
|
||||||
|
super::computed::ClipRect {
|
||||||
|
top: self.top.to_computed_value(context),
|
||||||
|
right: self.right.as_ref().map(|right| right.to_computed_value(context)),
|
||||||
|
bottom: self.bottom.as_ref().map(|bottom| bottom.to_computed_value(context)),
|
||||||
|
left: self.left.to_computed_value(context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_computed_value(computed: &super::computed::ClipRect) -> Self {
|
||||||
|
ClipRect {
|
||||||
|
top: ToComputedValue::from_computed_value(&computed.top),
|
||||||
|
right: computed.right.map(|right| ToComputedValue::from_computed_value(&right)),
|
||||||
|
bottom: computed.bottom.map(|bottom| ToComputedValue::from_computed_value(&bottom)),
|
||||||
|
left: ToComputedValue::from_computed_value(&computed.left),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for ClipRect {
|
||||||
|
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
|
use values::specified::Length;
|
||||||
|
|
||||||
|
fn parse_argument(context: &ParserContext, input: &mut Parser) -> Result<Option<Length>, ()> {
|
||||||
|
if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Length::parse(context, input).map(Some)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !try!(input.expect_function()).eq_ignore_ascii_case("rect") {
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NB: `top` and `left` are 0 if `auto` per CSS 2.1 11.1.2.
|
||||||
|
input.parse_nested_block(|input| {
|
||||||
|
let top = try!(parse_argument(context, input));
|
||||||
|
let right;
|
||||||
|
let bottom;
|
||||||
|
let left;
|
||||||
|
|
||||||
|
if input.try(|input| input.expect_comma()).is_ok() {
|
||||||
|
right = try!(parse_argument(context, input));
|
||||||
|
try!(input.expect_comma());
|
||||||
|
bottom = try!(parse_argument(context, input));
|
||||||
|
try!(input.expect_comma());
|
||||||
|
left = try!(parse_argument(context, input));
|
||||||
|
} else {
|
||||||
|
right = try!(parse_argument(context, input));
|
||||||
|
bottom = try!(parse_argument(context, input));
|
||||||
|
left = try!(parse_argument(context, input));
|
||||||
|
}
|
||||||
|
Ok(ClipRect {
|
||||||
|
top: top.unwrap_or(Length::zero()),
|
||||||
|
right: right,
|
||||||
|
bottom: bottom,
|
||||||
|
left: left.unwrap_or(Length::zero()),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// rect(...) | auto
|
||||||
|
pub type ClipRectOrAuto = Either<ClipRect, Auto>;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue