Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Introduce #[css(skip_if)] #20236

Merged
merged 7 commits into from Mar 8, 2018
@@ -15,31 +15,29 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu
// decimal-leading-zero, armenian, upper-armenian, lower-armenian, georgian, lower-roman,
// upper-roman
//
// TODO(bholley): Missing quite a few gecko properties here as well.
//
// In gecko, {upper,lower}-{roman,alpha} are implemented as @counter-styles in the
// UA, however they can also be set from pres attrs. When @counter-style is supported
// we may need to look into this and handle these differently.
//
// [1]: http://dev.w3.org/csswg/css-counter-styles/
% if product == "servo":
${helpers.single_keyword("list-style-type", """
disc none circle square decimal disclosure-open disclosure-closed lower-alpha upper-alpha
${helpers.single_keyword(
"list-style-type",
"""disc none circle square decimal disclosure-open disclosure-closed lower-alpha upper-alpha
arabic-indic bengali cambodian cjk-decimal devanagari gujarati gurmukhi kannada khmer lao
malayalam mongolian myanmar oriya persian telugu thai tibetan cjk-earthly-branch
cjk-heavenly-stem lower-greek hiragana hiragana-iroha katakana katakana-iroha""",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type",
servo_restyle_damage="rebuild_and_reflow")}
servo_restyle_damage="rebuild_and_reflow",
)}
% else:
${helpers.predefined_type("list-style-type",
"ListStyleType",
"computed::ListStyleType::disc()",
initial_specified_value="specified::ListStyleType::disc()",
animation_value_type="discrete",
boxed=True,
spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.predefined_type(
"list-style-type",
"ListStyleType",
"computed::ListStyleType::disc()",
initial_specified_value="specified::ListStyleType::disc()",
animation_value_type="discrete",
boxed=True,
spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type",
servo_restyle_damage="rebuild_and_reflow",
)}
% endif

${helpers.predefined_type("list-style-image",
@@ -80,21 +80,24 @@ pub struct TransformOrigin<H, V, Depth> {
/// A generic timing function.
///
/// <https://drafts.csswg.org/css-timing-1/#single-timing-function-production>
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)]
pub enum TimingFunction<Integer, Number> {
/// `linear | ease | ease-in | ease-out | ease-in-out`
Keyword(TimingKeyword),
/// `cubic-bezier(<number>, <number>, <number>, <number>)`
#[allow(missing_docs)]
#[css(comma, function)]
CubicBezier {
x1: Number,
y1: Number,
x2: Number,
y2: Number,
},
/// `step-start | step-end | steps(<integer>, [ start | end ]?)`
Steps(Integer, StepPosition),
#[css(comma, function)]
Steps(Integer, #[css(skip_if = "is_end")] StepPosition),
/// `frames(<integer>)`
#[css(comma, function)]
Frames(Integer),
}

@@ -119,6 +122,11 @@ pub enum StepPosition {
End,
}

#[inline]
fn is_end(position: &StepPosition) -> bool {
*position == StepPosition::End
}

impl<H, V, D> TransformOrigin<H, V, D> {
/// Returns a new transform origin.
pub fn new(horizontal: H, vertical: V, depth: D) -> Self {
@@ -138,51 +146,6 @@ impl<Integer, Number> TimingFunction<Integer, Number> {
}
}

impl<Integer, Number> ToCss for TimingFunction<Integer, Number>
where
Integer: ToCss,
Number: ToCss,
{
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
match *self {
TimingFunction::Keyword(keyword) => keyword.to_css(dest),
TimingFunction::CubicBezier {
ref x1,
ref y1,
ref x2,
ref y2,
} => {
dest.write_str("cubic-bezier(")?;
x1.to_css(dest)?;
dest.write_str(", ")?;
y1.to_css(dest)?;
dest.write_str(", ")?;
x2.to_css(dest)?;
dest.write_str(", ")?;
y2.to_css(dest)?;
dest.write_str(")")
},
TimingFunction::Steps(ref intervals, position) => {
dest.write_str("steps(")?;
intervals.to_css(dest)?;
if position != StepPosition::End {
dest.write_str(", ")?;
position.to_css(dest)?;
}
dest.write_str(")")
},
TimingFunction::Frames(ref frames) => {
dest.write_str("frames(")?;
frames.to_css(dest)?;
dest.write_str(")")
},
}
}
}

impl TimingKeyword {
/// Returns the keyword as a quadruplet of Bezier point coordinates
/// `(x1, y1, x2, y2)`.
@@ -5,7 +5,7 @@
use cg::{self, WhereClause};
use darling::util::Override;
use quote::{ToTokens, Tokens};
use syn::{self, Data};
use syn::{self, Data, Path};
use synstructure::{BindingInfo, Structure, VariantInfo};

pub fn derive(input: syn::DeriveInput) -> Tokens {
@@ -79,7 +79,6 @@ fn derive_variant_arm(

let mut expr = if let Some(keyword) = variant_attrs.keyword {
assert!(bindings.is_empty());
let keyword = keyword.to_string();
quote! {
::std::fmt::Write::write_str(dest, #keyword)
}
@@ -129,7 +128,15 @@ fn derive_variant_fields_expr(
if !attrs.ignore_bound {
where_clause.add_trait_bound(&first.ast().ty);
}
return quote! { ::style_traits::ToCss::to_css(#first, dest) };
let mut expr = quote! { ::style_traits::ToCss::to_css(#first, dest) };
if let Some(condition) = attrs.skip_if {
expr = quote! {
if !#condition(#first) {
#expr
}
}
}
return expr;
}

let mut expr = derive_single_field_expr(first, attrs, where_clause);
@@ -149,7 +156,7 @@ fn derive_single_field_expr(
attrs: CssFieldAttrs,
where_clause: &mut WhereClause,
) -> Tokens {
if attrs.iterable {
let mut expr = if attrs.iterable {
if let Some(if_empty) = attrs.if_empty {
return quote! {
{
@@ -174,7 +181,17 @@ fn derive_single_field_expr(
where_clause.add_trait_bound(&field.ast().ty);
}
quote! { writer.item(#field)?; }
};

if let Some(condition) = attrs.skip_if {
expr = quote! {
if !#condition(#field) {
#expr
}
}
}

expr
}

#[darling(attributes(css), default)]
@@ -204,4 +221,5 @@ struct CssFieldAttrs {
ignore_bound: bool,
iterable: bool,
skip: bool,
skip_if: Option<Path>,
}
@@ -34,6 +34,9 @@ use std::fmt::{self, Write};
/// dimension token, like: <member><identifier>;
/// * if `#[css(skip)]` is found on a field, the `ToCss` call for that field
/// is skipped;
/// * if `#[css(skip_if = "function")]` is found on a field, the `ToCss` call
/// for that field is skipped if `function` returns true. This function is
/// provided the field as an argument;
/// * finally, one can put `#[css(derive_debug)]` on the whole type, to
/// implement `Debug` by a single call to `ToCss::to_css`.
pub trait ToCss {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.