/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
<%! from data import to_rust_ident, to_camel_case, SYSTEM_FONT_LONGHANDS %>
<%def name="longhand(property)"> /// ${property.spec} pubmod ${property.ident} { #[allow(unused_imports)] usecrate::derives::*; #[allow(unused_imports)] usecrate::values::{computed, generics, specified}; #[allow(unused_imports)] usecrate::values::computed::ToComputedValue; #[allow(unused_imports)] use servo_arc::Arc; use cssparser::Parser; #[allow(unused_imports)] usecrate::parser::{Parse, ParserContext}; use style_traits::ParseError; #[allow(unused_imports)] usecrate::properties::{longhands, LonghandId, CSSWideKeyword, PropertyDeclaration};
#[allow(unused_variables)] pubunsafefn cascade_property(
declaration: &PropertyDeclaration,
context: &mut computed::Context,
) {
% if property.logical:
declaration.debug_crash("Should physicalize before entering here");
% else:
context.for_non_inherited_property = ${"false"if property.style_struct.inherited else"true"};
% if property.logical_group:
debug_assert_eq!(
declaration.id().as_longhand().unwrap().logical_group(),
LonghandId::${property.camel_case}.logical_group(),
);
% else:
debug_assert_eq!(
declaration.id().as_longhand().unwrap(),
LonghandId::${property.camel_case},
);
% endif let specified_value = match *declaration {
PropertyDeclaration::CSSWideKeyword(ref wk) => { match wk.keyword {
% if not property.style_struct.inherited:
CSSWideKeyword::Unset |
% endif
CSSWideKeyword::Initial => {
% if not property.style_struct.inherited:
declaration.debug_crash("Unexpected initial or unset for non-inherited property");
% else:
context.builder.reset_${property.ident}();
% endif
},
% if property.style_struct.inherited:
CSSWideKeyword::Unset |
% endif
CSSWideKeyword::Inherit => {
% if not property.style_struct.inherited:
context.rule_cache_conditions.borrow_mut().set_uncacheable();
% endif
% if property.is_zoom_dependent(): if !context.builder.effective_zoom_for_inheritance.is_one() { let old_zoom = context.builder.effective_zoom;
context.builder.effective_zoom = context.builder.effective_zoom_for_inheritance; let computed = context.builder.inherited_style.clone_${property.ident}(); let specified = computed::ToComputedValue::from_computed_value(&computed);
% if property.boxed: let specified = Box::new(specified);
% endif let decl = PropertyDeclaration::${property.camel_case}(specified);
cascade_property(&decl, context);
context.builder.effective_zoom = old_zoom; return;
}
% endif
% if property.style_struct.inherited:
declaration.debug_crash("Unexpected inherit or unset for non-zoom-dependent inherited property");
% else:
context.builder.inherit_${property.ident}();
% endif
}
CSSWideKeyword::RevertRule |
CSSWideKeyword::RevertLayer |
CSSWideKeyword::Revert => {
declaration.debug_crash("Found revert* not dealt with");
},
} return;
}, #[cfg(debug_assertions)]
PropertyDeclaration::WithVariables(..) => {
declaration.debug_crash("Found variables not substituted"); return;
},
_ => unsafe {
declaration.unchecked_value_as::<${property.specified_type()}>()
},
};
% if property.ident in SYSTEM_FONT_LONGHANDS and engine == "gecko": iflet Some(sf) = specified_value.get_system() { crate::properties::gecko::system_font::resolve_system_font(sf, context);
}
% endif
% if property.vector and not property.vector.simple_bindings and engine == "gecko": // In the case of a vector property we want to pass down an // iterator so that this can be computed without allocation. // // However, computing requires a context, but the style struct // being mutated is on the context. We temporarily remove it, // mutate it, and then put it back. Vector longhands cannot // touch their own style struct whilst computing, else this will // panic. letmut s =
context.builder.take_${property.style_struct.name_lower}();
{ let iter = specified_value.compute_iter(context);
s.set_${property.ident}(iter);
}
context.builder.put_${property.style_struct.name_lower}(s);
% else:
% if property.boxed: let computed = (**specified_value).to_computed_value(context);
% else: let computed = specified_value.to_computed_value(context);
% endif
context.builder.set_${property.ident}(computed)
% endif
% endif
}
#[cfg(feature = "gecko")] impl SpecifiedValue { /// Obtain a specified value from a Gecko keyword value /// /// Intended for use with presentation attributes, not style structs pubfn from_gecko_keyword(kw: u32) -> Self { usecrate::gecko_bindings::structs;
% for value in property.keyword.values_for(engine): // We can't match on enum values if we're matching on a u32 const ${to_rust_ident(value).upper()}: u32 = structs::${property.keyword.gecko_constant(value)} as u32;
% endfor match kw {
% for value in property.keyword.values_for(engine):
${to_rust_ident(value).upper()} => Self::${to_camel_case(value)},
% endfor
_ => panic!("Found unexpected value in style struct for ${property.name} property"),
}
}
}
% endif
% if property.vector:
} // single_value
% endif
// The setup here is roughly: // // * UnderlyingList is the list that is stored in the computed value. This may // be a shared ArcSlice if the property is inherited. // * UnderlyingOwnedList is the list that is used for animation. // * Specified values always use OwnedSlice, since it's more compact. // * computed_value::List is just a convenient alias that you can use for the // computed value list, since this is in the computed_value module. // // If vector.simple_bindings is true, then we don't use the complex iterator // machinery and set_foo_from, and just compute the value like any other // longhand.
% if property.vector:
<% allow_empty = not property.initial_value and not property.keyword %> #[allow(unused_imports)] use smallvec::SmallVec;
/// The definition of the computed value for ${property.name}. pubmod computed_value { #[allow(unused_imports)] usecrate::values::animated::ToAnimatedValue; #[allow(unused_imports)] usecrate::values::resolved::ToResolvedValue; #[allow(unused_imports)] usecrate::derives::*; pubusesuper::single_value::computed_value as single_value; pubuseself::single_value::T as SingleComputedValue;
% if not allow_empty: use smallvec::SmallVec;
% endif usecrate::values::computed::ComputedVecIter;
<% is_shared_list = allow_empty and property.style_struct.inherited %>
// FIXME(emilio): Add an OwnedNonEmptySlice type, and figure out // something for transition-name, which is the only remaining user // of NotInitial. pubtype UnderlyingList<T> =
% if allow_empty:
% if property.style_struct.inherited: crate::ArcSlice<T>;
% else: crate::OwnedSlice<T>;
% endif
% else:
SmallVec<[T; 1]>;
% endif
/// The generic type defining the animated and resolved values 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. #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToResolvedValue, ToCss, ToTyped)]
% if property.vector.separator == "Comma": #[css(comma)]
% endif pubstruct OwnedList<T>(
% if not allow_empty: #[css(iterable)]
% else: #[css(if_empty = "none", iterable)]
% endif pub UnderlyingOwnedList<T>,
);
/// The computed value for this property.
% if not is_shared_list: pubtype ComputedList = OwnedList<single_value::T>; pubuseself::OwnedList as List;
% else: pubuseself::ComputedList as List;
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToTyped)]
% if property.vector.separator == "Comma": #[css(comma)]
% endif pubstruct ComputedList(
% if not allow_empty: #[css(iterable)]
% else: #[css(if_empty = "none", iterable)]
% endif
% if is_shared_list: #[ignore_malloc_size_of = "Arc"]
% endif pub UnderlyingList<single_value::T>,
);
type ResolvedList = <OwnedList<single_value::T> as ToResolvedValue>::ResolvedValue; impl ToResolvedValue for ComputedList { type ResolvedValue = ResolvedList;
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
% if not is_shared_list: use std::iter::FromIterator;
% endif let iter =
resolved.0.into_iter().map(ToResolvedValue::from_resolved_value);
ComputedList(UnderlyingList::from_iter(iter))
}
}
% endif
% if property.vector.animation_type: usecrate::values::animated::{Animate, ToAnimatedZero, Procedure, lists}; usecrate::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 = <OwnedList<single_value::T> as ToAnimatedValue>::AnimatedValue;
% if is_shared_list: impl ToAnimatedValue for ComputedList { type AnimatedValue = AnimatedList;
impl ToComputedValue for SpecifiedValue { type ComputedValue = computed_value::T;
#[inline] fn to_computed_value(&self, context: &computed::Context) -> computed_value::T {
% if not is_shared_list: use std::iter::FromIterator;
% endif
computed_value::List(computed_value::UnderlyingList::from_iter( self.0.iter().map(|i| i.to_computed_value(context))
))
}
#[inline] fn from_computed_value(computed: &computed_value::T) -> Self { let iter = computed.0.iter().map(ToComputedValue::from_computed_value);
SpecifiedValue(iter.collect())
}
}
% endif
}
</%def>
<%def name="shorthand(shorthand)"> /// ${shorthand.spec} pubmod ${shorthand.ident} { #[allow(unused_imports)] usecrate::derives::*; usecrate::parser::ParserContext; usecrate::properties::{PropertyDeclaration, SourcePropertyDeclaration, longhands}; use cssparser::Parser; #[allow(unused_imports)] use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss, ParseError};
% if shorthand.derive_value_info: #[derive(SpecifiedValueInfo)]
% endif pubstruct Longhands {
% for sub_property in shorthand.sub_properties: pub ${sub_property.ident}:
% if sub_property.boxed: Box<
% endif
longhands::${sub_property.ident}::SpecifiedValue
% if sub_property.boxed:
>
% endif
,
% endfor
}
/// Represents a serializable set of all of the longhand properties that /// correspond to a shorthand.
% if shorthand.derive_serialize: #[derive(ToCss)]
% endif pubstruct LonghandsToSerialize<'a> {
% for sub_property in shorthand.sub_properties: pub ${sub_property.ident}:
% if sub_property.may_be_disabled_in(shorthand, engine):
Option<
% endif
&'a longhands::${sub_property.ident}::SpecifiedValue,
% if sub_property.may_be_disabled_in(shorthand, engine):
>,
% endif
% endfor
}
impl<'a> LonghandsToSerialize<'a> { /// Tries to get a serializable set of longhands given a set of /// property declarations. pubfn from_iter(iter: impl Iterator<Item = &'a PropertyDeclaration>) -> Result<Self, ()> { // Define all of the expected variables that correspond to the shorthand
% for sub_property in shorthand.sub_properties: letmut ${sub_property.ident} =
None::<&'a longhands::${sub_property.ident}::SpecifiedValue>;
% endfor
// Attempt to assign the incoming declarations to the expected variables for declaration in iter { match *declaration {
% for sub_property in shorthand.sub_properties:
PropertyDeclaration::${sub_property.camel_case}(ref value) => {
${sub_property.ident} = Some(value)
},
% endfor
_ => {}
};
}
// If any of the expected variables are missing, return an error match (
% for sub_property in shorthand.sub_properties:
${sub_property.ident},
% endfor
) {
(
% for sub_property in shorthand.sub_properties:
% if sub_property.may_be_disabled_in(shorthand, engine):
${sub_property.ident},
% else:
Some(${sub_property.ident}),
% endif
% endfor
) =>
Ok(LonghandsToSerialize {
% for sub_property in shorthand.sub_properties:
${sub_property.ident},
% endfor
}),
_ => Err(())
}
}
}
/// Parse the given shorthand and fill the result into the /// `declarations` vector. pubfn parse_into<'i, 't>(
declarations: &mut SourcePropertyDeclaration,
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<(), ParseError<'i>> { #[allow(unused_imports)] usecrate::properties::{NonCustomPropertyId, LonghandId};
% if not shorthand.kind: usecrate::properties::shorthands::${shorthand.ident}::parse_value;
% endif
input.parse_entirely(|input| parse_value(context, input)).map(|longhands| {
% for sub_property in shorthand.sub_properties:
% if sub_property.may_be_disabled_in(shorthand, engine): if NonCustomPropertyId::from(LonghandId::${sub_property.camel_case})
.allowed_in_ignoring_rule_type(context) {
% endif
declarations.push(PropertyDeclaration::${sub_property.camel_case}(
longhands.${sub_property.ident}
));
% if sub_property.may_be_disabled_in(shorthand, engine):
}
% endif
% endfor
})
}
/// Try to serialize a given shorthand to a string. pubfn to_css(declarations: &[&PropertyDeclaration], dest: &mut style_traits::CssStringWriter) -> fmt::Result { match LonghandsToSerialize::from_iter(declarations.iter().cloned()) {
Ok(longhands) => longhands.to_css(&mut CssWriter::new(dest)),
Err(_) => Ok(())
}
}
% if shorthand.kind == "two_properties":
${self.two_properties_shorthand(shorthand)}
% endif
% if shorthand.kind == "four_sides":
${self.four_sides_shorthand(shorthand)}
% endif
% if shorthand.kind == "single_border":
${self.single_border_shorthand(shorthand)}
% endif
}
</%def>
// A shorthand of kind `<property-1> <property-2>?` where both properties have // the same type.
<%def name="two_properties_shorthand(shorthand)"> type Single = crate::properties::longhands::${shorthand.sub_properties[0].ident}::SpecifiedValue;
fn parse_value<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Longhands, ParseError<'i>> { let first = <Single ascrate::parser::Parse>::parse(context, input)?; let second =
input.try_parse(|input| <Single ascrate::parser::Parse>::parse(context, input)).unwrap_or_else(|_| first.clone());
Ok(crate::properties::shorthands::expanded! {
${shorthand.sub_properties[0].ident}: first,
${shorthand.sub_properties[1].ident}: second,
})
}
impl<'a> ToCss for LonghandsToSerialize<'a> { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write { let first = &self.${shorthand.sub_properties[0].ident}; let second = &self.${shorthand.sub_properties[1].ident};
first.to_css(dest)?; if first != second {
dest.write_char(' ')?;
second.to_css(dest)?;
}
Ok(())
}
}
</%def>
type Single = crate::properties::longhands::${shorthand.sub_properties[0].ident}::SpecifiedValue; fn parse_value<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Longhands, ParseError<'i>> { let rect = Rect::parse_with(context, input, |c, i| -> Result<Single, ParseError<'i> > {
% if shorthand.allow_quirks:
Single::parse_quirky(c, i, crate::values::specified::AllowQuirks::Yes)
% else:
<Single ascrate::parser::Parse>::parse(c, i)
% endif
})?;
Ok(crate::properties::shorthands::expanded! {
% for index in range(4):
${shorthand.sub_properties[index].ident}: rect.${index},
% endfor
})
}
impl<'a> ToCss for LonghandsToSerialize<'a> { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where
W: fmt::Write,
{ let rect = Rect::new(
% for index in range(4):
&self.${shorthand.sub_properties[index].ident},
% endfor
);
rect.to_css(dest)
}
}
</%def>
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.