/* 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 Keyword, to_rust_ident, to_phys, to_camel_case, SYSTEM_FONT_LONGHANDS
from data import (LOGICAL_CORNERS, PHYSICAL_CORNERS, LOGICAL_SIDES,
PHYSICAL_SIDES, LOGICAL_SIZES, LOGICAL_AXES)
%>
// 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 simple_vector_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.
<%def name="vector_longhand(name, vector_animation_type=None, allow_empty=False,
none_value=None, simple_vector_bindings=False, separator='Comma',
**kwargs)">
<%call expr="longhand(name, vector=True,
simple_vector_bindings=simple_vector_bindings, **kwargs)"> #[allow(unused_imports)] use smallvec::SmallVec;
pubmod single_value { #[allow(unused_imports)] use cssparser::{Parser, BasicParseError}; #[allow(unused_imports)] usecrate::parser::{Parse, ParserContext}; #[allow(unused_imports)] usecrate::properties::ShorthandId; #[allow(unused_imports)] use selectors::parser::SelectorParseErrorKind; #[allow(unused_imports)] use style_traits::{ParseError, StyleParseErrorKind}; #[allow(unused_imports)] usecrate::values::computed::{Context, ToComputedValue}; #[allow(unused_imports)] usecrate::values::{computed, specified};
${caller.body()}
}
/// The definition of the computed value for ${name}. pubmod computed_value { #[allow(unused_imports)] usecrate::values::animated::ToAnimatedValue; #[allow(unused_imports)] usecrate::values::resolved::ToResolvedValue; 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 \
data.longhands_by_name[name].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 data.longhands_by_name[name].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)]
% if 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)]
% if 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 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: &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())
}
}
</%call>
</%def>
<%def name="longhand(*args, **kwargs)">
<%
property = data.declare_longhand(*args, **kwargs) if property is None: return""
%> /// ${property.spec} pubmod ${property.ident} { #[allow(unused_imports)] use cssparser::{Parser, BasicParseError, Token}; #[allow(unused_imports)] usecrate::parser::{Parse, ParserContext}; #[allow(unused_imports)] usecrate::properties::{UnparsedValue, ShorthandId}; #[allow(unused_imports)] usecrate::error_reporting::ParseErrorReporter; #[allow(unused_imports)] usecrate::properties::longhands; #[allow(unused_imports)] usecrate::properties::{LonghandId, LonghandIdSet}; #[allow(unused_imports)] usecrate::properties::{CSSWideKeyword, ComputedValues, PropertyDeclaration}; #[allow(unused_imports)] usecrate::properties::style_structs; #[allow(unused_imports)] use selectors::parser::SelectorParseErrorKind; #[allow(unused_imports)] use servo_arc::Arc; #[allow(unused_imports)] use style_traits::{ParseError, StyleParseErrorKind}; #[allow(unused_imports)] usecrate::values::computed::{Context, ToComputedValue}; #[allow(unused_imports)] usecrate::values::{computed, generics, specified}; #[allow(unused_imports)] usecrate::Atom;
${caller.body()} #[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 property.style_struct.inherited:
declaration.debug_crash("Unexpected inherit or unset for inherited property");
% else:
context.rule_cache_conditions.borrow_mut().set_uncacheable();
context.builder.inherit_${property.ident}();
% endif
}
CSSWideKeyword::RevertLayer |
CSSWideKeyword::Revert => {
declaration.debug_crash("Found revert/revert-layer not deal 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() {
longhands::system_font::resolve_system_font(sf, context);
}
% endif
% if property.is_vector and not property.simple_vector_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_${data.current_style_struct.name_lower}();
{ let iter = specified_value.compute_iter(context);
s.set_${property.ident}(iter);
}
context.builder.put_${data.current_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
}
<%def name="gecko_keyword_conversion(keyword, values=None, type='SpecifiedValue', cast_to=None)">
<% if not values:
values = keyword.values_for(engine)
maybe_cast = "as %s" % cast_to if cast_to else""
const_type = cast_to if cast_to else"u32"
%> #[cfg(feature = "gecko")] impl ${type} { /// 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 values: // We can't match on enum values if we're matching on a u32 const ${to_rust_ident(value).upper()}: ${const_type}
= structs::${keyword.gecko_constant(value)} as ${const_type};
% endfor match kw ${maybe_cast} {
% for value in values:
${to_rust_ident(value).upper()} => ${type}::${to_camel_case(value)},
% endfor
_ => panic!("Found unexpected value in style struct for ${keyword.name} property"),
}
}
}
</%def>
<%def name="gecko_bitflags_conversion(bit_map, gecko_bit_prefix, type, kw_type='u8')"> #[cfg(feature = "gecko")] impl ${type} { /// Obtain a specified value from a Gecko keyword value /// /// Intended for use with presentation attributes, not style structs pubfn from_gecko_keyword(kw: ${kw_type}) -> Self {
% for gecko_bit in bit_map.values(): usecrate::gecko_bindings::structs::${gecko_bit_prefix}${gecko_bit};
% endfor
letmut bits = ${type}::empty();
% for servo_bit, gecko_bit in bit_map.items(): if kw & (${gecko_bit_prefix}${gecko_bit} as ${kw_type}) != 0 {
bits |= ${servo_bit};
}
% endfor
bits
}
pubfn to_gecko_keyword(self) -> ${kw_type} {
% for gecko_bit in bit_map.values(): usecrate::gecko_bindings::structs::${gecko_bit_prefix}${gecko_bit};
% endfor
letmut bits: ${kw_type} = 0; // FIXME: if we ensure that the Servo bitflags storage is the same // as Gecko's one, we can just copy it.
% for servo_bit, gecko_bit in bit_map.items(): ifself.contains(${servo_bit}) {
bits |= ${gecko_bit_prefix}${gecko_bit} as ${kw_type};
}
% endfor
bits
}
}
</%def>
<%def name="single_keyword(name, values, vector=False,
needs_conversion=False, **kwargs)">
<%
keyword_kwargs = {a: kwargs.pop(a, None) for a in [ 'gecko_constant_prefix', 'gecko_enum_prefix', 'extra_gecko_values', 'extra_servo_values', 'gecko_aliases', 'servo_aliases', 'custom_consts', 'gecko_inexhaustive', 'gecko_strip_moz_prefix',
]}
%>
<%def name="shorthand(name, sub_properties, derive_serialize=False,
derive_value_info=True, **kwargs)">
<%
shorthand = data.declare_shorthand(name, sub_properties.split(), **kwargs) # mako doesn't accept non-string value in parameters with <% %> form, so # we have to workaround it this way. if not isinstance(derive_value_info, bool):
derive_value_info = eval(derive_value_info)
%>
% if shorthand: /// ${shorthand.spec} pubmod ${shorthand.ident} { use cssparser::Parser; usecrate::parser::ParserContext; usecrate::properties::{PropertyDeclaration, SourcePropertyDeclaration, MaybeBoxed, longhands}; #[allow(unused_imports)] use selectors::parser::SelectorParseErrorKind; #[allow(unused_imports)] use std::fmt::{self, Write}; #[allow(unused_imports)] use style_traits::{ParseError, StyleParseErrorKind}; #[allow(unused_imports)] use style_traits::{CssWriter, KeywordsCollectFn, SpecifiedValueInfo, ToCss};
% if 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 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};
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: &mutcrate::str::CssStringWriter) -> fmt::Result { match LonghandsToSerialize::from_iter(declarations.iter().cloned()) {
Ok(longhands) => longhands.to_css(&mut CssWriter::new(dest)),
Err(_) => Ok(())
}
}
${caller.body()}
}
% endif
</%def>
// A shorthand of kind `<property-1> <property-2>?` where both properties have // the same type.
<%def name="two_properties_shorthand(
name,
first_property,
second_property,
parser_function='crate::parser::Parse::parse',
**kwargs
)">
<%call expr="self.shorthand(name, sub_properties=' '.join([first_property, second_property]), **kwargs)"> #[allow(unused_imports)] usecrate::parser::Parse; #[allow(unused_imports)] usecrate::values::specified;
let first = parse_one(context, input)?; let second =
input.try_parse(|input| parse_one(context, input)).unwrap_or_else(|_| first.clone());
Ok(expanded! {
${to_rust_ident(first_property)}: first,
${to_rust_ident(second_property)}: 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.${to_rust_ident(first_property)}; let second = &self.${to_rust_ident(second_property)};
first.to_css(dest)?; if first != second {
dest.write_char(' ')?;
second.to_css(dest)?;
}
Ok(())
}
}
</%call>
</%def>
<%def name="four_sides_shorthand(name, sub_property_pattern,
parser_function='crate::parser::Parse::parse',
allow_quirks='No', **kwargs)">
<% sub_properties=' '.join(sub_property_pattern % side for side in PHYSICAL_SIDES) %>
<%call expr="self.shorthand(name, sub_properties=sub_properties, **kwargs)"> #[allow(unused_imports)] usecrate::parser::Parse; usecrate::values::generics::rect::Rect; #[allow(unused_imports)] usecrate::values::specified;
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< crate::properties::longhands::${to_rust_ident(sub_property_pattern % "top")}::SpecifiedValue,
ParseError<'i>
> {
% if allow_quirks != "No":
${parser_function}_quirky(c, i, specified::AllowQuirks::${allow_quirks})
% else:
${parser_function}(c, i)
% endif
})?;
Ok(expanded! {
% for index, side in enumerate(["top", "right", "bottom", "left"]):
${to_rust_ident(sub_property_pattern % side)}: rect.${index},
% endfor
})
}
impl<'a> ToCss for LonghandsToSerialize<'a> { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where
W: Write,
{ let rect = Rect::new(
% for side in ["top", "right", "bottom", "left"]:
&self.${to_rust_ident(sub_property_pattern % side)},
% endfor
);
rect.to_css(dest)
}
}
</%call>
</%def>
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-06-18)
¤
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.