Merge inbound to central, a=merge
MozReview-Commit-ID: HpVAbc2vi78
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */// This file is a Mako template: http://www.makotemplates.org/// Please note that valid Rust syntax may be mangled by the Mako parser.// For example, Vec<&Foo> will be mangled as Vec&Foo>. To work around these issues, the code// can be escaped. In the above example, Vec<<&Foo> or Vec< &Foo> achieves the desired result of Vec<&Foo>.<%namespacename="helpers"file="/helpers.mako.rs"/>#[cfg(feature = "servo")]useapp_units::Au;useservo_arc::{Arc,UniqueArc};usestd::borrow::Cow;usestd::collections::HashSet;usestd::{fmt,mem,ops};#[cfg(feature = "gecko")]usestd::ptr;#[cfg(feature = "servo")]usecssparser::RGBA;usecssparser::{Parser,TokenSerializationType,serialize_identifier};usecssparser::ParserInput;#[cfg(feature = "servo")]useeuclid::SideOffsets2D;usecomputed_values;usecontext::QuirksMode;useerror_reporting::NullReporter;usefont_metrics::FontMetricsProvider;#[cfg(feature = "gecko")]usegecko_bindings::bindings;#[cfg(feature = "gecko")]usegecko_bindings::structs::{self,nsCSSPropertyID};#[cfg(feature = "servo")]uselogical_geometry::{LogicalMargin,PhysicalSide};uselogical_geometry::WritingMode;usemedia_queries::Device;useparser::ParserContext;useproperties::animated_properties::AnimatableLonghand;#[cfg(feature = "gecko")]useproperties::longhands::system_font::SystemFont;useselector_parser::PseudoElement;useselectors::parser::SelectorParseError;#[cfg(feature = "servo")]useservo_config::prefs::PREFS;useshared_lock::StylesheetGuards;usestyle_traits::{PARSING_MODE_DEFAULT,HasViewportPercentage,ToCss,ParseError};usestyle_traits::{PropertyDeclarationParseError,StyleParseError,ValueParseError};usestylesheets::{CssRuleType,MallocSizeOf,MallocSizeOfFn,Origin,UrlExtraData};#[cfg(feature = "servo")]usevalues::Either;usevalues::generics::text::LineHeight;usevalues::computed;usevalues::computed::NonNegativeAu;usecascade_info::CascadeInfo;userule_tree::{CascadeLevel,StrongRuleNode};useself::computed_value_flags::ComputedValueFlags;usestyle_adjuster::StyleAdjuster;#[cfg(feature = "servo")]usevalues::specified::BorderStyle;pubuseself::declaration_block::*;#[cfg(feature = "gecko")]#[macro_export]macro_rules!property_name{($s:tt)=>{atom!($s)}}#[cfg(feature = "gecko")]macro_rules!impl_bitflags_conversions{($name:ident)=>{implFrom<u8>for$name{fnfrom(bits:u8)->$name{$name::from_bits(bits).expect("bits contain valid flag")}}implFrom<$name>foru8{fnfrom(v:$name)->u8{v.bits()}}};}<%!fromdataimportMethod,Keyword,to_rust_ident,to_camel_case,SYSTEM_FONT_LONGHANDSimportos.path%>#[path="${repr(os.path.join(os.path.dirname(__file__), 'computed_value_flags.rs'))[1:-1]}"]pubmodcomputed_value_flags;#[path="${repr(os.path.join(os.path.dirname(__file__), 'declaration_block.rs'))[1:-1]}"]pubmoddeclaration_block;/// Conversion with fewer impls than From/IntopubtraitMaybeBoxed<Out>{/// Convertfnmaybe_boxed(self)->Out;}/// This is where we store extra font data while/// while computing font sizes.#[derive(Clone, Debug)]pubstructFontComputationData{/// font-size keyword values (and font-size-relative values applied/// to keyword values) need to preserve their identity as originating/// from keywords and relative font sizes. We store this information/// out of band in the ComputedValues. When None, the font size on the/// current struct was computed from a value that was not a keyword/// or a chain of font-size-relative values applying to successive parents/// terminated by a keyword. When Some, this means the font-size was derived/// from a keyword value or a keyword value on some ancestor with only/// font-size-relative keywords and regular inheritance in between. The/// integer stores the final ratio of the chain of font size relative values./// and is 1 when there was just a keyword and no relative values.////// When this is Some, we compute font sizes by computing the keyword against/// the generic font, and then multiplying it by the ratio.pubfont_size_keyword:Option<(longhands::font_size::KeywordSize,f32)>}implFontComputationData{/// Assigns values for variables in struct FontComputationDatapubfnnew(font_size_keyword:Option<(longhands::font_size::KeywordSize,f32)>)->Self{FontComputationData{font_size_keyword:font_size_keyword}}/// Assigns default values for variables in struct FontComputationDatapubfndefault_font_size_keyword()->Option<(longhands::font_size::KeywordSize,f32)>{Some((Default::default(),1.))}/// Gets a FontComputationData with the default values.pubfndefault_values()->Self{Self::new(Self::default_font_size_keyword())}}impl<T>MaybeBoxed<T>forT{#[inline]fnmaybe_boxed(self)->T{self}}impl<T>MaybeBoxed<Box<T>>forT{#[inline]fnmaybe_boxed(self)->Box<T>{Box::new(self)}}macro_rules!expanded{($($name:ident:$value:expr),+)=>{expanded!($($name:$value,)+)};($($name:ident:$value:expr,)+)=>{Longhands{$($name:MaybeBoxed::maybe_boxed($value),)+}}}/// A module with all the code for longhand properties.#[allow(missing_docs)]pubmodlonghands{<%includefile="/longhand/background.mako.rs"/><%includefile="/longhand/border.mako.rs"/><%includefile="/longhand/box.mako.rs"/><%includefile="/longhand/color.mako.rs"/><%includefile="/longhand/column.mako.rs"/><%includefile="/longhand/counters.mako.rs"/><%includefile="/longhand/effects.mako.rs"/><%includefile="/longhand/font.mako.rs"/><%includefile="/longhand/inherited_box.mako.rs"/><%includefile="/longhand/inherited_table.mako.rs"/><%includefile="/longhand/inherited_text.mako.rs"/><%includefile="/longhand/list.mako.rs"/><%includefile="/longhand/margin.mako.rs"/><%includefile="/longhand/outline.mako.rs"/><%includefile="/longhand/padding.mako.rs"/><%includefile="/longhand/pointing.mako.rs"/><%includefile="/longhand/position.mako.rs"/><%includefile="/longhand/table.mako.rs"/><%includefile="/longhand/text.mako.rs"/><%includefile="/longhand/ui.mako.rs"/><%includefile="/longhand/inherited_svg.mako.rs"/><%includefile="/longhand/svg.mako.rs"/><%includefile="/longhand/xul.mako.rs"/>}macro_rules!unwrap_or_initial{($prop:ident)=>(unwrap_or_initial!($prop,$prop));($prop:ident,$expr:expr)=>($expr.unwrap_or_else(||$prop::get_initial_specified_value()));}/// A module with code for all the shorthand css properties, and a few/// serialization helpers.#[allow(missing_docs)]pubmodshorthands{usecssparser::Parser;useparser::{Parse,ParserContext};usestyle_traits::{ParseError,StyleParseError};usevalues::specified;<%includefile="/shorthand/serialize.mako.rs"/><%includefile="/shorthand/background.mako.rs"/><%includefile="/shorthand/border.mako.rs"/><%includefile="/shorthand/box.mako.rs"/><%includefile="/shorthand/column.mako.rs"/><%includefile="/shorthand/font.mako.rs"/><%includefile="/shorthand/inherited_text.mako.rs"/><%includefile="/shorthand/list.mako.rs"/><%includefile="/shorthand/margin.mako.rs"/><%includefile="/shorthand/mask.mako.rs"/><%includefile="/shorthand/outline.mako.rs"/><%includefile="/shorthand/padding.mako.rs"/><%includefile="/shorthand/position.mako.rs"/><%includefile="/shorthand/inherited_svg.mako.rs"/><%includefile="/shorthand/text.mako.rs"/>// We don't defined the 'all' shorthand using the regular helpers:shorthand// mechanism, since it causes some very large types to be generated.<%data.declare_shorthand("all",[p.nameforpindata.longhandsifp.namenotin['direction','unicode-bidi']],spec="https://drafts.csswg.org/css-cascade-3/#all-shorthand")%>}/// A module with all the code related to animated properties.////// This needs to be "included" by mako at least after all longhand modules,/// given they populate the global data.pubmodanimated_properties{<%includefile="/helpers/animated_properties.mako.rs"/>}/// A longhand or shorthand porperty#[derive(Copy, Clone, Debug)]pubstructNonCustomPropertyId(usize);implFrom<LonghandId>forNonCustomPropertyId{fnfrom(id:LonghandId)->Self{NonCustomPropertyId(idasusize)}}implFrom<ShorthandId>forNonCustomPropertyId{fnfrom(id:ShorthandId)->Self{NonCustomPropertyId((idasusize)+${len(data.longhands)})}}/// A set of longhand properties#[derive(Clone, PartialEq)]pubstructNonCustomPropertyIdSet{storage:[u32;(${len(data.longhands)+len(data.shorthands)}-1+32)/32]}implNonCustomPropertyIdSet{/// Return whether the given property is in the set#[inline]pubfncontains(&self,id:NonCustomPropertyId)->bool{letbit=id.0;(self.storage[bit/32]&(1<<(bit%32)))!=0}}<%defname="static_non_custom_property_id_set(name, is_member)">static${name}:NonCustomPropertyIdSet=NonCustomPropertyIdSet{<%storage=[0]*((len(data.longhands)+len(data.shorthands)-1+32)/32)fori,propertyinenumerate(data.longhands+data.shorthands):ifis_member(property):storage[i/32]|=1<<(i%32)%>storage:[${", ".join("0x%x"%wordforwordinstorage)}]};</%def><%defname="static_longhand_id_set(name, is_member)">static${name}:LonghandIdSet=LonghandIdSet{<%storage=[0]*((len(data.longhands)-1+32)/32)fori,propertyinenumerate(data.longhands):ifis_member(property):storage[i/32]|=1<<(i%32)%>storage:[${", ".join("0x%x"%wordforwordinstorage)}]};</%def>/// A set of longhand properties#[derive(Clone, PartialEq)]pubstructLonghandIdSet{storage:[u32;(${len(data.longhands)}-1+32)/32]}implLonghandIdSet{/// Create an empty set#[inline]pubfnnew()->LonghandIdSet{LonghandIdSet{storage:[0;(${len(data.longhands)}-1+32)/32]}}/// Return whether the given property is in the set#[inline]pubfncontains(&self,id:LonghandId)->bool{letbit=idasusize;(self.storage[bit/32]&(1<<(bit%32)))!=0}/// Add the given property to the set#[inline]pubfninsert(&mutself,id:LonghandId){letbit=idasusize;self.storage[bit/32]|=1<<(bit%32);}/// Remove the given property from the set#[inline]pubfnremove(&mutself,id:LonghandId){letbit=idasusize;self.storage[bit/32]&=!(1<<(bit%32));}/// Clear all bits#[inline]pubfnclear(&mutself){forcellin&mutself.storage{*cell=0}}/// Set the corresponding bit of AnimatableLonghand.pubfnset_animatable_longhand_bit(&mutself,property:&AnimatableLonghand){match*property{%forpropindata.longhands:%ifprop.animatable:AnimatableLonghand::${prop.camel_case}=>self.insert(LonghandId::${prop.camel_case}),%endif%endfor}}/// Return true if the corresponding bit of AnimatableLonghand is set.pubfnhas_animatable_longhand_bit(&self,property:&AnimatableLonghand)->bool{match*property{%forpropindata.longhands:%ifprop.animatable:AnimatableLonghand::${prop.camel_case}=>self.contains(LonghandId::${prop.camel_case}),%endif%endfor}}}/// A specialized set of PropertyDeclarationIdpubstructPropertyDeclarationIdSet{longhands:LonghandIdSet,// FIXME: Use a HashSet instead? This Vec is usually small, so linear scan might be ok.custom:Vec<::custom_properties::Name>,}implPropertyDeclarationIdSet{/// Empty setpubfnnew()->Self{PropertyDeclarationIdSet{longhands:LonghandIdSet::new(),custom:Vec::new(),}}/// Returns whether the given ID is in the setpubfncontains(&mutself,id:PropertyDeclarationId)->bool{matchid{PropertyDeclarationId::Longhand(id)=>self.longhands.contains(id),PropertyDeclarationId::Custom(name)=>self.custom.contains(name),}}/// Insert the given ID in the setpubfninsert(&mutself,id:PropertyDeclarationId){matchid{PropertyDeclarationId::Longhand(id)=>self.longhands.insert(id),PropertyDeclarationId::Custom(name)=>{if!self.custom.contains(name){self.custom.push(name.clone())}}}}}/// An enum to represent a CSS Wide keyword.#[cfg_attr(feature = "servo", derive(HeapSizeOf))]#[derive(Copy, Clone, Debug, Eq, PartialEq, ToCss)]pubenumCSSWideKeyword{/// The `initial` keyword.Initial,/// The `inherit` keyword.Inherit,/// The `unset` keyword.Unset,}implCSSWideKeyword{fnto_str(&self)->&'staticstr{match*self{CSSWideKeyword::Initial=>"initial",CSSWideKeyword::Inherit=>"inherit",CSSWideKeyword::Unset=>"unset",}}/// Takes the result of cssparser::Parser::expect_ident() and converts it/// to a CSSWideKeyword.pubfnfrom_ident<'i>(ident:&str)->Option<Self>{match_ignore_ascii_case!{ident,// If modifying this set of keyword, also update values::CustomIdent::from_ident"initial"=>Some(CSSWideKeyword::Initial),"inherit"=>Some(CSSWideKeyword::Inherit),"unset"=>Some(CSSWideKeyword::Unset),_=>None}}}implCSSWideKeyword{fnparse(input:&mutParser)->Result<Self,()>{letident=input.expect_ident().map_err(|_|())?.clone();input.expect_exhausted().map_err(|_|())?;CSSWideKeyword::from_ident(&ident).ok_or(())}}bitflags!{/// A set of flags for properties.pubflagsPropertyFlags:u8{/// This property requires a stacking context.constCREATES_STACKING_CONTEXT=1<<0,/// This property has values that can establish a containing block for/// fixed positioned and absolutely positioned elements.constFIXPOS_CB=1<<1,/// This property has values that can establish a containing block for/// absolutely positioned elements.constABSPOS_CB=1<<2,/// This shorthand property is an alias of another property.constSHORTHAND_ALIAS_PROPERTY=1<<3,/// This longhand property applies to ::first-letter.constAPPLIES_TO_FIRST_LETTER=1<<4,/// This longhand property applies to ::first-line.constAPPLIES_TO_FIRST_LINE=1<<5,/// This longhand property applies to ::placeholder.constAPPLIES_TO_PLACEHOLDER=1<<6,}}/// An identifier for a given longhand property.#[derive(Clone, Copy, Eq, PartialEq, Debug)]#[cfg_attr(feature = "servo", derive(HeapSizeOf))]pubenumLonghandId{%fori,propertyinenumerate(data.longhands):/// ${property.name}${property.camel_case}=${i},%endfor}implLonghandId{/// Get the name of this longhand property.pubfnname(&self)->&'staticstr{match*self{%forpropertyindata.longhands:LonghandId::${property.camel_case}=>"${property.name}",%endfor}}fninherited(&self)->bool{${static_longhand_id_set("INHERITED",lambdap:p.style_struct.inherited)}INHERITED.contains(*self)}fnshorthands(&self)->&'static[ShorthandId]{// first generate longhand to shorthands lookup map//// NOTE(emilio): This currently doesn't exclude the "all" shorthand. It// could potentially do so, which would speed up serialization// algorithms and what not, I guess.<%longhand_to_shorthand_map={}forshorthandindata.shorthands:forsub_propertyinshorthand.sub_properties:ifsub_property.identnotinlonghand_to_shorthand_map:longhand_to_shorthand_map[sub_property.ident]=[]longhand_to_shorthand_map[sub_property.ident].append(shorthand.camel_case)forshorthand_listinlonghand_to_shorthand_map.itervalues():shorthand_list.sort()%>// based on lookup results for each longhand, create result arrays%forpropertyindata.longhands:static${property.ident.upper()}:&'static[ShorthandId]=&[%forshorthandinlonghand_to_shorthand_map.get(property.ident,[]):ShorthandId::${shorthand},%endfor];%endformatch*self{%forpropertyindata.longhands:LonghandId::${property.camel_case}=>${property.ident.upper()},%endfor}}fnparse_value<'i,'t>(&self,context:&ParserContext,input:&mutParser<'i,'t>)->Result<PropertyDeclaration,ParseError<'i>>{match*self{%forpropertyindata.longhands:LonghandId::${property.camel_case}=>{%ifnotproperty.derived_from:longhands::${property.ident}::parse_declared(context,input)%else:Err(PropertyDeclarationParseError::UnknownProperty("${property.ident}".into()).into())%endif}%endfor}}/// If this is a logical property, return the corresponding physical one in the given writing mode./// Otherwise, return unchanged.pubfnto_physical(&self,wm:WritingMode)->Self{match*self{%forpropertyindata.longhands:%ifproperty.logical:LonghandId::${property.camel_case}=>{<%helpers:logical_setter_helpername="${property.name}"><%defname="inner(physical_ident)">LonghandId::${to_camel_case(physical_ident)}</%def></%helpers:logical_setter_helper>}%endif%endfor_=>*self}}/// Returns PropertyFlags for given longhand property.pubfnflags(&self)->PropertyFlags{match*self{%forpropertyindata.longhands:LonghandId::${property.camel_case}=>%forflaginproperty.flags:${flag}|%endforPropertyFlags::empty(),%endfor}}/// Only a few properties are allowed to depend on the visited state of/// links. When cascading visited styles, we can save time by only/// processing these properties.fnis_visited_dependent(&self)->bool{matches!(*self,%ifproduct=="gecko":LonghandId::ColumnRuleColor|LonghandId::TextEmphasisColor|LonghandId::WebkitTextFillColor|LonghandId::WebkitTextStrokeColor|LonghandId::TextDecorationColor|LonghandId::Fill|LonghandId::Stroke|LonghandId::CaretColor|%endifLonghandId::Color|LonghandId::BackgroundColor|LonghandId::BorderTopColor|LonghandId::BorderRightColor|LonghandId::BorderBottomColor|LonghandId::BorderLeftColor|LonghandId::OutlineColor)}/// Returns true if the property is one that is ignored when document/// colors are disabled.fnis_ignored_when_document_colors_disabled(&self)->bool{matches!(*self,${" | ".join([("LonghandId::"+p.camel_case)forpindata.longhandsifp.ignored_when_colors_disabled])})}/// The computed value of some properties depends on the (sometimes/// computed) value of *other* properties.////// So we classify properties into "early" and "other", such that the only/// dependencies can be from "other" to "early".////// Unfortunately, it’s not easy to check that this classification is/// correct.fnis_early_property(&self)->bool{matches!(*self,%ifproduct=='gecko':LonghandId::TextOrientation|LonghandId::AnimationName|LonghandId::TransitionProperty|LonghandId::XLang|LonghandId::XTextZoom|LonghandId::MozScriptLevel|LonghandId::MozMinFontSizeRatio|%endifLonghandId::FontSize|LonghandId::FontFamily|LonghandId::Color|LonghandId::TextDecorationLine|LonghandId::WritingMode|LonghandId::Direction)}}/// An identifier for a given shorthand property.#[cfg_attr(feature = "servo", derive(HeapSizeOf))]#[derive(Clone, Copy, Debug, Eq, PartialEq, ToCss)]pubenumShorthandId{%forpropertyindata.shorthands:/// ${property.name}${property.camel_case},%endfor}implShorthandId{/// Get the name for this shorthand property.pubfnname(&self)->&'staticstr{match*self{%forpropertyindata.shorthands:ShorthandId::${property.camel_case}=>"${property.name}",%endfor}}/// Get the longhand ids that form this shorthand.pubfnlonghands(&self)->&'static[LonghandId]{%forpropertyindata.shorthands:static${property.ident.upper()}:&'static[LonghandId]=&[%forsubinproperty.sub_properties:LonghandId::${sub.camel_case},%endfor];%endformatch*self{%forpropertyindata.shorthands:ShorthandId::${property.camel_case}=>${property.ident.upper()},%endfor}}/// Try to serialize the given declarations as this shorthand.////// Returns an error if writing to the stream fails, or if the declarations/// do not map to a shorthand.pubfnlonghands_to_css<'a,W,I>(&self,declarations:I,dest:&mutW)->fmt::ResultwhereW:fmt::Write,I:Iterator<Item=&'aPropertyDeclaration>,{match*self{ShorthandId::All=>{// No need to try to serialize the declarations as the 'all'// shorthand, since it only accepts CSS-wide keywords (and// variable references), which will be handled in// get_shorthand_appendable_value.Err(fmt::Error)}%forpropertyindata.shorthands_except_all():ShorthandId::${property.camel_case}=>{matchshorthands::${property.ident}::LonghandsToSerialize::from_iter(declarations){Ok(longhands)=>longhands.to_css(dest),Err(_)=>Err(fmt::Error)}},%endfor}}/// Finds and returns an appendable value for the given declarations.////// Returns the optional appendable value.pubfnget_shorthand_appendable_value<'a,I>(self,declarations:I)->Option<AppendableValue<'a,I::IntoIter>>whereI:IntoIterator<Item=&'aPropertyDeclaration>,I::IntoIter:Clone,{letdeclarations=declarations.into_iter();// Only cloning iterators (a few pointers each) not declarations.letmutdeclarations2=declarations.clone();letmutdeclarations3=declarations.clone();letfirst_declaration=matchdeclarations2.next(){Some(declaration)=>declaration,None=>returnNone};// https://drafts.csswg.org/css-variables/#variables-in-shorthandsifletSome(css)=first_declaration.with_variables_from_shorthand(self){ifdeclarations2.all(|d|d.with_variables_from_shorthand(self)==Some(css)){returnSome(AppendableValue::Css{css:css,with_variables:true,});}returnNone;}// Check whether they are all the same CSS-wide keyword.ifletSome(keyword)=first_declaration.get_css_wide_keyword(){ifdeclarations2.all(|d|d.get_css_wide_keyword()==Some(keyword)){returnSome(AppendableValue::Css{css:keyword.to_str(),with_variables:false,});}returnNone;}// Check whether all declarations can be serialized as part of shorthand.ifdeclarations3.all(|d|d.may_serialize_as_part_of_shorthand()){returnSome(AppendableValue::DeclarationsForShorthand(self,declarations));}None}/// Returns PropertyFlags for given shorthand property.pubfnflags(&self)->PropertyFlags{match*self{%forpropertyindata.shorthands:ShorthandId::${property.camel_case}=>%forflaginproperty.flags:${flag}|%endforPropertyFlags::empty(),%endfor}}fnparse_into<'i,'t>(&self,declarations:&mutSourcePropertyDeclaration,context:&ParserContext,input:&mutParser<'i,'t>)->Result<(),ParseError<'i>>{match*self{%forshorthandindata.shorthands_except_all():ShorthandId::${shorthand.camel_case}=>{shorthands::${shorthand.ident}::parse_into(declarations,context,input)}%endfor// 'all' accepts no value other than CSS-wide keywordsShorthandId::All=>Err(StyleParseError::UnspecifiedError.into())}}}/// Servo's representation of a declared value for a given `T`, which is the/// declared value for that property.#[derive(Clone, PartialEq, Eq, Debug)]pubenumDeclaredValue<'a,T:'a>{/// A known specified value from the stylesheet.Value(&'aT),/// An unparsed value that contains `var()` functions.WithVariables(&'aArc<UnparsedValue>),/// An CSS-wide keyword.CSSWideKeyword(CSSWideKeyword),}/// A variant of DeclaredValue that owns its data. This separation exists so/// that PropertyDeclaration can avoid embedding a DeclaredValue (and its/// extra discriminant word) and synthesize dependent DeclaredValues for/// PropertyDeclaration instances as needed.#[derive(Clone, PartialEq, Eq, Debug)]pubenumDeclaredValueOwned<T>{/// A known specified value from the stylesheet.Value(T),/// An unparsed value that contains `var()` functions.WithVariables(Arc<UnparsedValue>),/// An CSS-wide keyword.CSSWideKeyword(CSSWideKeyword),}impl<T>DeclaredValueOwned<T>{/// Creates a dependent DeclaredValue from this DeclaredValueOwned.fnborrow(&self)->DeclaredValue<T>{match*self{DeclaredValueOwned::Value(refv)=>DeclaredValue::Value(v),DeclaredValueOwned::WithVariables(refv)=>DeclaredValue::WithVariables(v),DeclaredValueOwned::CSSWideKeyword(v)=>DeclaredValue::CSSWideKeyword(v),}}}/// An unparsed property value that contains `var()` functions.#[derive(PartialEq, Eq, Debug)]pubstructUnparsedValue{/// The css serialization for this value.css:String,/// The first token type for this serialization.first_token_type:TokenSerializationType,/// The url data for resolving url values.url_data:UrlExtraData,/// The shorthand this came from.from_shorthand:Option<ShorthandId>,}implUnparsedValue{fnsubstitute_variables(&self,longhand_id:LonghandId,custom_properties:&Option<Arc<::custom_properties::CustomPropertiesMap>>,quirks_mode:QuirksMode)->PropertyDeclaration{::custom_properties::substitute(&self.css,self.first_token_type,custom_properties).ok().and_then(|css|{// As of this writing, only the base URL is used for property values:letreporter=NullReporter;letcontext=ParserContext::new(Origin::Author,&self.url_data,&reporter,None,PARSING_MODE_DEFAULT,quirks_mode);letmutinput=ParserInput::new(&css);Parser::new(&mutinput).parse_entirely(|input|{matchself.from_shorthand{None=>longhand_id.parse_value(&context,input),Some(ShorthandId::All)=>{// No need to parse the 'all' shorthand as anything other than a CSS-wide// keyword, after variable substitution.Err(SelectorParseError::UnexpectedIdent("all".into()).into())}%forshorthandindata.shorthands_except_all():Some(ShorthandId::${shorthand.camel_case})=>{shorthands::${shorthand.ident}::parse_value(&context,input).map(|longhands|{matchlonghand_id{%forpropertyinshorthand.sub_properties:LonghandId::${property.camel_case}=>{PropertyDeclaration::${property.camel_case}(longhands.${property.ident})}%endfor_=>unreachable!()}})}%endfor}}).ok()}).unwrap_or_else(||{// Invalid at computed-value time.letkeyword=iflonghand_id.inherited(){CSSWideKeyword::Inherit}else{CSSWideKeyword::Initial};PropertyDeclaration::CSSWideKeyword(longhand_id,keyword)})}}impl<'a,T:HasViewportPercentage>HasViewportPercentageforDeclaredValue<'a,T>{fnhas_viewport_percentage(&self)->bool{match*self{DeclaredValue::Value(refv)=>v.has_viewport_percentage(),DeclaredValue::WithVariables(_)=>{panic!("DeclaredValue::has_viewport_percentage without \ resolving variables!")},DeclaredValue::CSSWideKeyword(_)=>false,}}}impl<'a,T:ToCss>ToCssforDeclaredValue<'a,T>{fnto_css<W>(&self,dest:&mutW)->fmt::ResultwhereW:fmt::Write,{match*self{DeclaredValue::Value(refinner)=>inner.to_css(dest),DeclaredValue::WithVariables(refwith_variables)=>{// https://drafts.csswg.org/css-variables/#variables-in-shorthandsifwith_variables.from_shorthand.is_none(){dest.write_str(&*with_variables.css)?}Ok(())},DeclaredValue::CSSWideKeyword(refkeyword)=>keyword.to_css(dest),}}}/// An identifier for a given property declaration, which can be either a/// longhand or a custom property.#[derive(PartialEq, Clone, Copy)]#[cfg_attr(feature = "servo", derive(HeapSizeOf))]pubenumPropertyDeclarationId<'a>{/// A longhand.Longhand(LonghandId),/// A custom property declaration.Custom(&'a::custom_properties::Name),}impl<'a>ToCssforPropertyDeclarationId<'a>{fnto_css<W>(&self,dest:&mutW)->fmt::ResultwhereW:fmt::Write,{match*self{PropertyDeclarationId::Longhand(id)=>dest.write_str(id.name()),PropertyDeclarationId::Custom(_)=>{serialize_identifier(&self.name(),dest)}}}}impl<'a>PropertyDeclarationId<'a>{/// Whether a given declaration id is either the same as `other`, or a/// longhand of it.pubfnis_or_is_longhand_of(&self,other:&PropertyId)->bool{match*self{PropertyDeclarationId::Longhand(id)=>{match*other{PropertyId::Longhand(other_id)=>id==other_id,PropertyId::Shorthand(shorthand)=>self.is_longhand_of(shorthand),PropertyId::Custom(_)=>false,}}PropertyDeclarationId::Custom(name)=>{matches!(*other,PropertyId::Custom(refother_name)ifname==other_name)}}}/// Whether a given declaration id is a longhand belonging to this/// shorthand.pubfnis_longhand_of(&self,shorthand:ShorthandId)->bool{match*self{PropertyDeclarationId::Longhand(refid)=>id.shorthands().contains(&shorthand),_=>false,}}/// Returns the name of the property without CSS escaping.pubfnname(&self)->Cow<'static,str>{match*self{PropertyDeclarationId::Longhand(id)=>id.name().into(),PropertyDeclarationId::Custom(name)=>{usestd::fmt::Write;letmuts=String::new();write!(&muts,"--{}",name).unwrap();s.into()}}}}/// Servo's representation of a CSS property, that is, either a longhand, a/// shorthand, or a custom property.#[derive(Eq, PartialEq, Clone)]pubenumPropertyId{/// A longhand property.Longhand(LonghandId),/// A shorthand property.Shorthand(ShorthandId),/// A custom property.Custom(::custom_properties::Name),}implfmt::DebugforPropertyId{fnfmt(&self,formatter:&mutfmt::Formatter)->fmt::Result{self.to_css(formatter)}}implToCssforPropertyId{fnto_css<W>(&self,dest:&mutW)->fmt::ResultwhereW:fmt::Write,{match*self{PropertyId::Longhand(id)=>dest.write_str(id.name()),PropertyId::Shorthand(id)=>dest.write_str(id.name()),PropertyId::Custom(_)=>{serialize_identifier(&self.name(),dest)}}}}implPropertyId{/// Returns a given property from the string `s`.////// Returns Err(()) for unknown non-custom propertiespubfnparse(property_name:&str)->Result<Self,()>{ifletOk(name)=::custom_properties::parse_name(property_name){returnOk(PropertyId::Custom(::custom_properties::Name::from(name)))}// FIXME(https://github.com/rust-lang/rust/issues/33156): remove this enum and use PropertyId// when stable Rust allows destructors in statics.pubenumStaticId{Longhand(LonghandId),Shorthand(ShorthandId),}ascii_case_insensitive_phf_map!{static_id->StaticId={%for(kind,properties)in[("Longhand",data.longhands),("Shorthand",data.shorthands)]:%forpropertyinproperties:%fornamein[property.name]+property.alias:"${name}"=>StaticId::${kind}(${kind}Id::${property.camel_case}),%endfor%endfor%endfor}}matchstatic_id(property_name){Some(&StaticId::Longhand(id))=>Ok(PropertyId::Longhand(id)),Some(&StaticId::Shorthand(id))=>Ok(PropertyId::Shorthand(id)),None=>Err(()),}}/// Returns a property id from Gecko's nsCSSPropertyID.#[cfg(feature = "gecko")]#[allow(non_upper_case_globals)]pubfnfrom_nscsspropertyid(id:nsCSSPropertyID)->Result<Self,()>{usegecko_bindings::structs::*;matchid{%forpropertyindata.longhands:${helpers.to_nscsspropertyid(property.ident)}=>{Ok(PropertyId::Longhand(LonghandId::${property.camel_case}))}%foraliasinproperty.alias:${helpers.alias_to_nscsspropertyid(alias)}=>{Ok(PropertyId::Longhand(LonghandId::${property.camel_case}))}%endfor%endfor%forpropertyindata.shorthands:${helpers.to_nscsspropertyid(property.ident)}=>{Ok(PropertyId::Shorthand(ShorthandId::${property.camel_case}))}%foraliasinproperty.alias:${helpers.alias_to_nscsspropertyid(alias)}=>{Ok(PropertyId::Shorthand(ShorthandId::${property.camel_case}))}%endfor%endfor_=>Err(())}}/// Returns an nsCSSPropertyID.#[cfg(feature = "gecko")]#[allow(non_upper_case_globals)]pubfnto_nscsspropertyid(&self)->Result<nsCSSPropertyID,()>{usegecko_bindings::structs::*;match*self{PropertyId::Longhand(id)=>matchid{%forpropertyindata.longhands:LonghandId::${property.camel_case}=>{Ok(${helpers.to_nscsspropertyid(property.ident)})}%endfor},PropertyId::Shorthand(id)=>matchid{%forpropertyindata.shorthands:ShorthandId::${property.camel_case}=>{Ok(${helpers.to_nscsspropertyid(property.ident)})}%endfor},_=>Err(())}}/// Given this property id, get it either as a shorthand or as a/// `PropertyDeclarationId`.pubfnas_shorthand(&self)->Result<ShorthandId,PropertyDeclarationId>{match*self{PropertyId::Shorthand(id)=>Ok(id),PropertyId::Longhand(id)=>Err(PropertyDeclarationId::Longhand(id)),PropertyId::Custom(refname)=>Err(PropertyDeclarationId::Custom(name)),}}/// Returns the name of the property without CSS escaping.pubfnname(&self)->Cow<'static,str>{match*self{PropertyId::Shorthand(id)=>id.name().into(),PropertyId::Longhand(id)=>id.name().into(),PropertyId::Custom(refname)=>{usestd::fmt::Write;letmuts=String::new();write!(&muts,"--{}",name).unwrap();s.into()}}}fncheck_allowed_in(&self,rule_type:CssRuleType,stylesheet_origin:Origin)->Result<(),PropertyDeclarationParseError<'static>>{letid:NonCustomPropertyId;match*self{// Custom properties are allowed everywherePropertyId::Custom(_)=>returnOk(()),PropertyId::Shorthand(shorthand_id)=>id=shorthand_id.into(),PropertyId::Longhand(longhand_id)=>id=longhand_id.into(),}<%id_set=static_non_custom_property_id_set%>${id_set("DISALLOWED_IN_KEYFRAME_BLOCK",lambdap:notp.allowed_in_keyframe_block)}${id_set("DISALLOWED_IN_PAGE_RULE",lambdap:notp.allowed_in_page_rule)}matchrule_type{CssRuleType::KeyframeifDISALLOWED_IN_KEYFRAME_BLOCK.contains(id)=>{returnErr(PropertyDeclarationParseError::AnimationPropertyInKeyframeBlock)}CssRuleType::PageifDISALLOWED_IN_PAGE_RULE.contains(id)=>{returnErr(PropertyDeclarationParseError::NotAllowedInPageRule)}_=>{}}// For properties that are experimental but not internal, the pref will// control its availability in all sheets. For properties that are// both experimental and internal, the pref only controls its// availability in non-UA sheets (and in UA sheets it is always available).${id_set("INTERNAL",lambdap:p.internal)}%ifproduct=="servo":${id_set("EXPERIMENTAL",lambdap:p.experimental)}%endif%ifproduct=="gecko":usegecko_bindings::structs::root::mozilla;staticEXPERIMENTAL:NonCustomPropertyIdSet=NonCustomPropertyIdSet{<%grouped=[]properties=data.longhands+data.shorthandswhileproperties:grouped.append(properties[:32])properties=properties[32:]%>storage:[%forgroupingrouped:(0%fori,propertyinenumerate(group):|((mozilla::SERVO_PREF_ENABLED_${property.gecko_pref_ident}asu32)<<${i})%endfor),%endfor]};%endifletpasses_pref_check=||{%ifproduct=="servo":staticPREF_NAME:[Option<&str>;${len(data.longhands)+len(data.shorthands)}]=[%forpropertyindata.longhands+data.shorthands:%ifproperty.experimental:Some("${property.experimental}"),%else:None,%endif%endfor];matchPREF_NAME[id.0]{None=>true,Some(pref)=>PREFS.get(pref).as_boolean().unwrap_or(false)}%endif%ifproduct=="gecko":usegecko_bindings::structs;letid=self.to_nscsspropertyid().unwrap();unsafe{structs::nsCSSProps_gPropertyEnabled[idasusize]}%endif};ifINTERNAL.contains(id){ifstylesheet_origin!=Origin::UserAgent{ifEXPERIMENTAL.contains(id){if!passes_pref_check(){returnErr(PropertyDeclarationParseError::ExperimentalProperty);}}else{returnErr(PropertyDeclarationParseError::UnknownProperty(self.name().into()));}}}else{ifEXPERIMENTAL.contains(id)&&!passes_pref_check(){returnErr(PropertyDeclarationParseError::ExperimentalProperty);}}Ok(())}}/// Servo's representation for a property declaration.#[derive(PartialEq, Clone)]pubenumPropertyDeclaration{%forpropertyindata.longhands:/// ${property.name}%ifproperty.boxed:${property.camel_case}(Box<longhands::${property.ident}::SpecifiedValue>),%else:${property.camel_case}(longhands::${property.ident}::SpecifiedValue),%endif%endfor/// A css-wide keyword.CSSWideKeyword(LonghandId,CSSWideKeyword),/// An unparsed value that contains `var()` functions.WithVariables(LonghandId,Arc<UnparsedValue>),/// A custom property declaration, with the property name and the declared/// value.Custom(::custom_properties::Name,DeclaredValueOwned<Box<::custom_properties::SpecifiedValue>>),}implHasViewportPercentageforPropertyDeclaration{fnhas_viewport_percentage(&self)->bool{match*self{%forpropertyindata.longhands:PropertyDeclaration::${property.camel_case}(refval)=>{val.has_viewport_percentage()},%endforPropertyDeclaration::WithVariables(..)=>{panic!("DeclaredValue::has_viewport_percentage without \ resolving variables!")},PropertyDeclaration::CSSWideKeyword(..)=>false,PropertyDeclaration::Custom(_,refval)=>{val.borrow().has_viewport_percentage()}}}}implfmt::DebugforPropertyDeclaration{fnfmt(&self,f:&mutfmt::Formatter)->fmt::Result{self.id().to_css(f)?;f.write_str(": ")?;self.to_css(f)}}implToCssforPropertyDeclaration{fnto_css<W>(&self,dest:&mutW)->fmt::ResultwhereW:fmt::Write,{match*self{%forpropertyindata.longhands:%ifnotproperty.derived_from:PropertyDeclaration::${property.camel_case}(refvalue)=>value.to_css(dest),%endif%endforPropertyDeclaration::CSSWideKeyword(_,keyword)=>keyword.to_css(dest),PropertyDeclaration::WithVariables(_,refwith_variables)=>{// https://drafts.csswg.org/css-variables/#variables-in-shorthandsmatchwith_variables.from_shorthand{// Normally, we shouldn't be printing variables here if they came from// shorthands. But we should allow properties that came from shorthand// aliases. That also matches with the Gecko behavior.Some(shorthand)ifshorthand.flags().contains(SHORTHAND_ALIAS_PROPERTY)=>dest.write_str(&*with_variables.css)?,None=>dest.write_str(&*with_variables.css)?,_=>{},}Ok(())},PropertyDeclaration::Custom(_,refvalue)=>value.borrow().to_css(dest),%ifany(property.derived_fromforpropertyindata.longhands):_=>Err(fmt::Error),%endif}}}implMallocSizeOfforPropertyDeclaration{fnmalloc_size_of_children(&self,_malloc_size_of:MallocSizeOfFn)->usize{// The variants of PropertyDeclaration mostly (entirely?) contain// scalars, so this is reasonable.0}}implPropertyDeclaration{/// Given a property declaration, return the property declaration id.pubfnid(&self)->PropertyDeclarationId{match*self{PropertyDeclaration::Custom(refname,_)=>{returnPropertyDeclarationId::Custom(name)}PropertyDeclaration::CSSWideKeyword(id,_)|PropertyDeclaration::WithVariables(id,_)=>{returnPropertyDeclarationId::Longhand(id)}_=>{}}letlonghand_id=match*self{%forpropertyindata.longhands:PropertyDeclaration::${property.camel_case}(..)=>{LonghandId::${property.camel_case}}%endforPropertyDeclaration::CSSWideKeyword(..)|PropertyDeclaration::WithVariables(..)|PropertyDeclaration::Custom(..)=>{debug_assert!(false,"unreachable");// This value is never used, but having an expression of the same "shape"// as for other variants helps the optimizer compile this `match` expression// to a lookup table.LonghandId::BackgroundColor}};PropertyDeclarationId::Longhand(longhand_id)}fnwith_variables_from_shorthand(&self,shorthand:ShorthandId)->Option<&str>{match*self{PropertyDeclaration::WithVariables(_,refwith_variables)=>{ifletSome(s)=with_variables.from_shorthand{ifs==shorthand{Some(&*with_variables.css)}else{None}}else{// Normally, longhand property that doesn't come from a shorthand// should return None here. But we return Some to longhands if they// came from a shorthand alias. Because for example, we should be able to// get -moz-transform's value from transform.ifshorthand.flags().contains(SHORTHAND_ALIAS_PROPERTY){returnSome(&*with_variables.css);}None}},_=>None,}}/// Returns a CSS-wide keyword if the declaration's value is one.pubfnget_css_wide_keyword(&self)->Option<CSSWideKeyword>{match*self{PropertyDeclaration::CSSWideKeyword(_,keyword)=>Some(keyword),_=>None,}}/// Returns whether or not the property is set by a system font#[cfg(feature = "gecko")]pubfnget_system(&self)->Option<SystemFont>{match*self{%forpropinSYSTEM_FONT_LONGHANDS:PropertyDeclaration::${to_camel_case(prop)}(refprop)=>{prop.get_system()}%endfor_=>None,}}/// Is it the default value of line-height?pubfnis_default_line_height(&self)->bool{match*self{PropertyDeclaration::LineHeight(LineHeight::Normal)=>true,_=>false}}#[cfg(feature = "servo")]/// Dummy method to avoid cfg()spubfnget_system(&self)->Option<()>{None}/// Returns whether the declaration may be serialized as part of a shorthand.////// This method returns false if this declaration contains variable or has a/// CSS-wide keyword value, since these values cannot be serialized as part/// of a shorthand.////// Caller should check `with_variables_from_shorthand()` and whether all/// needed declarations has the same CSS-wide keyword first.////// Note that, serialization of a shorthand may still fail because of other/// property-specific requirement even when this method returns true for all/// the longhand declarations.pubfnmay_serialize_as_part_of_shorthand(&self)->bool{match*self{PropertyDeclaration::CSSWideKeyword(..)|PropertyDeclaration::WithVariables(..)=>false,PropertyDeclaration::Custom(..)=>unreachable!("Serializing a custom property as part of shorthand?"),_=>true,}}/// Return whether the value is stored as it was in the CSS source,/// preserving whitespace (as opposed to being parsed into a more abstract/// data structure).////// This is the case of custom properties and values that contain/// unsubstituted variables.pubfnvalue_is_unparsed(&self)->bool{match*self{PropertyDeclaration::WithVariables(..)=>true,PropertyDeclaration::Custom(_,refvalue)=>{!matches!(value.borrow(),DeclaredValue::CSSWideKeyword(..))}_=>false,}}/// The shorthands that this longhand is part of.pubfnshorthands(&self)->&'static[ShorthandId]{matchself.id(){PropertyDeclarationId::Longhand(id)=>id.shorthands(),PropertyDeclarationId::Custom(..)=>&[],}}/// Returns true if this property is one of the animable properties, false/// otherwise.pubfnis_animatable(&self)->bool{match*self{%forpropertyindata.longhands:PropertyDeclaration::${property.camel_case}(_)=>{%ifproperty.animatable:true%else:false%endif}%endforPropertyDeclaration::CSSWideKeyword(id,_)|PropertyDeclaration::WithVariables(id,_)=>matchid{%forpropertyindata.longhands:LonghandId::${property.camel_case}=>{%ifproperty.animatable:true%else:false%endif}%endfor},PropertyDeclaration::Custom(..)=>false,}}/// The `context` parameter controls this:////// https://drafts.csswg.org/css-animations/#keyframes/// > The <declaration-list> inside of <keyframe-block> accepts any CSS property/// > except those defined in this specification,/// > but does accept the `animation-play-state` property and interprets it specially.////// This will not actually parse Importance values, and will always set things/// to Importance::Normal. Parsing Importance values is the job of PropertyDeclarationParser,/// we only set them here so that we don't have to reallocatepubfnparse_into<'i,'t>(declarations:&mutSourcePropertyDeclaration,id:PropertyId,context:&ParserContext,input:&mutParser<'i,'t>)->Result<(),PropertyDeclarationParseError<'i>>{assert!(declarations.is_empty());letrule_type=context.rule_type();debug_assert!(rule_type==CssRuleType::Keyframe||rule_type==CssRuleType::Page||rule_type==CssRuleType::Style,"Declarations are only expected inside a keyframe, page, or style rule.");id.check_allowed_in(rule_type,context.stylesheet_origin)?;matchid{PropertyId::Custom(name)=>{letvalue=matchinput.try(|i|CSSWideKeyword::parse(i)){Ok(keyword)=>DeclaredValueOwned::CSSWideKeyword(keyword),Err(())=>match::custom_properties::SpecifiedValue::parse(context,input){Ok(value)=>DeclaredValueOwned::Value(value),Err(e)=>returnErr(PropertyDeclarationParseError::InvalidValue(name.to_string().into(),ValueParseError::from_parse_error(e))),}};declarations.push(PropertyDeclaration::Custom(name,value));Ok(())}PropertyId::Longhand(id)=>{input.try(|i|CSSWideKeyword::parse(i)).map(|keyword|{PropertyDeclaration::CSSWideKeyword(id,keyword)}).or_else(|()|{input.look_for_var_functions();letstart=input.position();input.parse_entirely(|input|id.parse_value(context,input)).or_else(|err|{whileletOk(_)=input.next(){}// Look for var() after the error.ifinput.seen_var_functions(){input.reset(start);let(first_token_type,css)=::custom_properties::parse_non_custom_with_var(input).map_err(|e|{PropertyDeclarationParseError::InvalidValue(id.name().into(),ValueParseError::from_parse_error(e))})?;Ok(PropertyDeclaration::WithVariables(id,Arc::new(UnparsedValue{css:css.into_owned(),first_token_type:first_token_type,url_data:context.url_data.clone(),from_shorthand:None,})))}else{Err(PropertyDeclarationParseError::InvalidValue(id.name().into(),ValueParseError::from_parse_error(err)))}})}).map(|declaration|{declarations.push(declaration)})}PropertyId::Shorthand(id)=>{ifletOk(keyword)=input.try(|i|CSSWideKeyword::parse(i)){ifid==ShorthandId::All{declarations.all_shorthand=AllShorthand::CSSWideKeyword(keyword)}else{for&longhandinid.longhands(){declarations.push(PropertyDeclaration::CSSWideKeyword(longhand,keyword))}}Ok(())}else{input.look_for_var_functions();letstart=input.position();// Not using parse_entirely here: each ${shorthand.ident}::parse_into function// needs to do so *before* pushing to `declarations`.id.parse_into(declarations,context,input).or_else(|err|{whileletOk(_)=input.next(){}// Look for var() after the error.ifinput.seen_var_functions(){input.reset(start);let(first_token_type,css)=::custom_properties::parse_non_custom_with_var(input).map_err(|e|{PropertyDeclarationParseError::InvalidValue(id.name().into(),ValueParseError::from_parse_error(e))})?;letunparsed=Arc::new(UnparsedValue{css:css.into_owned(),first_token_type:first_token_type,url_data:context.url_data.clone(),from_shorthand:Some(id),});ifid==ShorthandId::All{declarations.all_shorthand=AllShorthand::WithVariables(unparsed)}else{for&longhandinid.longhands(){declarations.push(PropertyDeclaration::WithVariables(longhand,unparsed.clone()))}}Ok(())}else{Err(PropertyDeclarationParseError::InvalidValue(id.name().into(),ValueParseError::from_parse_error(err)))}})}}}}}constMAX_SUB_PROPERTIES_PER_SHORTHAND_EXCEPT_ALL:usize=${max(len(s.sub_properties)forsindata.shorthands_except_all())};typeSourcePropertyDeclarationArray=[PropertyDeclaration;MAX_SUB_PROPERTIES_PER_SHORTHAND_EXCEPT_ALL];/// A stack-allocated vector of `PropertyDeclaration`/// large enough to parse one CSS `key: value` declaration./// (Shorthands expand to multiple `PropertyDeclaration`s.)pubstructSourcePropertyDeclaration{declarations:::arrayvec::ArrayVec<SourcePropertyDeclarationArray>,/// Stored separately to keep MAX_SUB_PROPERTIES_PER_SHORTHAND_EXCEPT_ALL smaller.all_shorthand:AllShorthand,}implSourcePropertyDeclaration{/// Create one. It’s big, try not to move it around.#[inline]pubfnnew()->Self{SourcePropertyDeclaration{declarations:::arrayvec::ArrayVec::new(),all_shorthand:AllShorthand::NotSet,}}/// Similar to Vec::drain: leaves this empty when the return value is dropped.pubfndrain(&mutself)->SourcePropertyDeclarationDrain{SourcePropertyDeclarationDrain{declarations:self.declarations.drain(..),all_shorthand:mem::replace(&mutself.all_shorthand,AllShorthand::NotSet),}}/// Reset to initial statepubfnclear(&mutself){self.declarations.clear();self.all_shorthand=AllShorthand::NotSet;}fnis_empty(&self)->bool{self.declarations.is_empty()&&matches!(self.all_shorthand,AllShorthand::NotSet)}fnpush(&mutself,declaration:PropertyDeclaration){letover_capacity=self.declarations.push(declaration).is_some();debug_assert!(!over_capacity);}}/// Return type of SourcePropertyDeclaration::drainpubstructSourcePropertyDeclarationDrain<'a>{declarations:::arrayvec::Drain<'a,SourcePropertyDeclarationArray>,all_shorthand:AllShorthand,}enumAllShorthand{NotSet,CSSWideKeyword(CSSWideKeyword),WithVariables(Arc<UnparsedValue>)}#[cfg(feature = "gecko")]pubusegecko_properties::style_structs;/// The module where all the style structs are defined.#[cfg(feature = "servo")]pubmodstyle_structs{usefnv::FnvHasher;usesuper::longhands;usestd::hash::{Hash,Hasher};uselogical_geometry::WritingMode;usemedia_queries::Device;usevalues::computed::NonNegativeAu;%forstyle_structindata.active_style_structs():%ifstyle_struct.name=="Font":#[derive(Clone, Debug)]%else:#[derive(PartialEq, Clone, Debug)]%endif#[cfg_attr(feature = "servo", derive(HeapSizeOf))]/// The ${style_struct.name} style struct.pubstruct${style_struct.name}{%forlonghandinstyle_struct.longhands:/// The ${longhand.name} computed value.pub${longhand.ident}:longhands::${longhand.ident}::computed_value::T,%endfor%ifstyle_struct.name=="Font":/// The font hash, used for font caching.pubhash:u64,%endif}%ifstyle_struct.name=="Font":implPartialEqfor${style_struct.name}{fneq(&self,other:&${style_struct.name})->bool{self.hash==other.hash%forlonghandinstyle_struct.longhands:&&self.${longhand.ident}==other.${longhand.ident}%endfor}}%endifimpl${style_struct.name}{%forlonghandinstyle_struct.longhands:%iflonghand.logical:${helpers.logical_setter(name=longhand.name)}%else:%iflonghand.is_vector:/// Set ${longhand.name}.#[allow(non_snake_case)]#[inline]pubfnset_${longhand.ident}<I>(&mutself,v:I)whereI:IntoIterator<Item=longhands::${longhand.ident}::computed_value::single_value::T>,I::IntoIter:ExactSizeIterator{self.${longhand.ident}=longhands::${longhand.ident}::computed_value::T(v.into_iter().collect());}%else:/// Set ${longhand.name}.#[allow(non_snake_case)]#[inline]pubfnset_${longhand.ident}(&mutself,v:longhands::${longhand.ident}::computed_value::T){self.${longhand.ident}=v;}%endif/// Set ${longhand.name} from other struct.#[allow(non_snake_case)]#[inline]pubfncopy_${longhand.ident}_from(&mutself,other:&Self){self.${longhand.ident}=other.${longhand.ident}.clone();}/// Reset ${longhand.name} from the initial struct.#[allow(non_snake_case)]#[inline]pubfnreset_${longhand.ident}(&mutself,other:&Self){self.copy_${longhand.ident}_from(other)}%iflonghand.need_clone:/// Get the computed value for ${longhand.name}.#[allow(non_snake_case)]#[inline]pubfnclone_${longhand.ident}(&self)->longhands::${longhand.ident}::computed_value::T{self.${longhand.ident}.clone()}%endif%endif%iflonghand.need_index:/// If this longhand is indexed, get the number of elements.#[allow(non_snake_case)]pubfn${longhand.ident}_count(&self)->usize{self.${longhand.ident}.0.len()}/// If this longhand is indexed, get the element at given/// index.#[allow(non_snake_case)]pubfn${longhand.ident}_at(&self,index:usize)->longhands::${longhand.ident}::computed_value::SingleComputedValue{self.${longhand.ident}.0[index].clone()}%endif%endfor%ifstyle_struct.name=="Border":%forsidein["top","right","bottom","left"]:/// Whether the border-${side} property has nonzero width.#[allow(non_snake_case)]pubfnborder_${side}_has_nonzero_width(&self)->bool{self.border_${side}_width!=NonNegativeAu::zero()}%endfor%elifstyle_struct.name=="Font":/// Computes a font hash in order to be able to cache fonts/// effectively in GFX and layout.pubfncompute_font_hash(&mutself){// Corresponds to the fields in// `gfx::font_template::FontTemplateDescriptor`.letmuthasher:FnvHasher=Default::default();hasher.write_u16(self.font_weight.0);self.font_stretch.hash(&muthasher);self.font_family.hash(&muthasher);self.hash=hasher.finish()}/// (Servo does not handle MathML, so this just calls copy_font_size_from)pubfninherit_font_size_from(&mutself,parent:&Self,_:Option<NonNegativeAu>,_:&Device)->bool{self.copy_font_size_from(parent);false}/// (Servo does not handle MathML, so this just calls set_font_size)pubfnapply_font_size(&mutself,v:longhands::font_size::computed_value::T,_:&Self,_:&Device)->Option<NonNegativeAu>{self.set_font_size(v);None}/// (Servo does not handle MathML, so this does nothing)pubfnapply_unconstrained_font_size(&mutself,_:NonNegativeAu){}%elifstyle_struct.name=="Outline":/// Whether the outline-width property is non-zero.#[inline]pubfnoutline_has_nonzero_width(&self)->bool{self.outline_width!=NonNegativeAu::zero()}%elifstyle_struct.name=="Text":/// Whether the text decoration has an underline.#[inline]pubfnhas_underline(&self)->bool{self.text_decoration_line.contains(longhands::text_decoration_line::UNDERLINE)}/// Whether the text decoration has an overline.#[inline]pubfnhas_overline(&self)->bool{self.text_decoration_line.contains(longhands::text_decoration_line::OVERLINE)}/// Whether the text decoration has a line through.#[inline]pubfnhas_line_through(&self)->bool{self.text_decoration_line.contains(longhands::text_decoration_line::LINE_THROUGH)}%elifstyle_struct.name=="Box":/// Sets the display property, but without touching/// __servo_display_for_hypothetical_box, except when the/// adjustment comes from root or item display fixups.pubfnset_adjusted_display(&mutself,dpy:longhands::display::computed_value::T,is_item_or_root:bool){self.set_display(dpy);ifis_item_or_root{self.set__servo_display_for_hypothetical_box(dpy);}}%endif}%endfor}%forstyle_structindata.active_style_structs():implstyle_structs::${style_struct.name}{%forlonghandinstyle_struct.longhands:%iflonghand.need_index:/// Iterate over the values of ${longhand.name}.#[allow(non_snake_case)]#[inline]pubfn${longhand.ident}_iter(&self)->${longhand.camel_case}Iter{${longhand.camel_case}Iter{style_struct:self,current:0,max:self.${longhand.ident}_count(),}}/// Get a value mod `index` for the property ${longhand.name}.#[allow(non_snake_case)]#[inline]pubfn${longhand.ident}_mod(&self,index:usize)->longhands::${longhand.ident}::computed_value::SingleComputedValue{self.${longhand.ident}_at(index%self.${longhand.ident}_count())}%endif%endfor%ifstyle_struct.name=="Box":/// Returns whether there is any animation specified with/// animation-name other than `none`.pubfnspecifies_animations(&self)->bool{self.animation_name_iter().any(|name|name.0.is_some())}/// Returns whether there are any transitions specified.#[cfg(feature = "servo")]pubfnspecifies_transitions(&self)->bool{self.transition_duration_iter().take(self.transition_property_count()).any(|t|t.seconds()>0.)}%endif}%forlonghandinstyle_struct.longhands:%iflonghand.need_index:/// An iterator over the values of the ${longhand.name} properties.pubstruct${longhand.camel_case}Iter<'a>{style_struct:&'astyle_structs::${style_struct.name},current:usize,max:usize,}impl<'a>Iteratorfor${longhand.camel_case}Iter<'a>{typeItem=longhands::${longhand.ident}::computed_value::SingleComputedValue;fnnext(&mutself)->Option<Self::Item>{self.current+=1;ifself.current<=self.max{Some(self.style_struct.${longhand.ident}_at(self.current-1))}else{None}}}%endif%endfor%endfor#[cfg(feature = "gecko")]pubusegecko_properties::{ComputedValues,ComputedValuesInner};#[cfg(feature = "servo")]#[cfg_attr(feature = "servo", derive(Clone, Debug))]/// Actual data of ComputedValues, to match up with GeckopubstructComputedValuesInner{%forstyle_structindata.active_style_structs():${style_struct.ident}:Arc<style_structs::${style_struct.name}>,%endforcustom_properties:Option<Arc<::custom_properties::CustomPropertiesMap>>,/// The writing mode of this computed values struct.pubwriting_mode:WritingMode,/// The keyword behind the current font-size property, if anypubfont_computation_data:FontComputationData,/// A set of flags we use to store misc information regarding this style.pubflags:ComputedValueFlags,/// The rule node representing the ordered list of rules matched for this/// node. Can be None for default values and text nodes. This is/// essentially an optimization to avoid referencing the root rule node.pubrules:Option<StrongRuleNode>,/// The element's computed values if visited, only computed if there's a/// relevant link for this element. A element's "relevant link" is the/// element being matched if it is a link or the nearest ancestor link.visited_style:Option<Arc<ComputedValues>>,}/// The struct that Servo uses to represent computed values.////// This struct contains an immutable atomically-reference-counted pointer to/// every kind of style struct.////// When needed, the structs may be copied in order to get mutated.#[cfg(feature = "servo")]#[cfg_attr(feature = "servo", derive(Clone, Debug))]pubstructComputedValues{/// The actual computed values////// In Gecko the outer ComputedValues is actually a style context,/// whereas ComputedValuesInner is the core set of computed values.////// We maintain this distinction in servo to reduce the amount of special casing.inner:ComputedValuesInner,}#[cfg(feature = "servo")]implComputedValues{/// Create a new refcounted `ComputedValues`pubfnnew(_:&Device,_:Option<<&ComputedValues>,_:Option<<&PseudoElement>,custom_properties:Option<Arc<::custom_properties::CustomPropertiesMap>>,writing_mode:WritingMode,font_size_keyword:Option<(longhands::font_size::KeywordSize,f32)>,flags:ComputedValueFlags,rules:Option<StrongRuleNode>,visited_style:Option<Arc<ComputedValues>>,%forstyle_structindata.active_style_structs():${style_struct.ident}:Arc<style_structs::${style_struct.name}>,%endfor)->Arc<Self>{Arc::new(Self{inner:ComputedValuesInner::new(custom_properties,writing_mode,font_size_keyword,flags,rules,visited_style,%forstyle_structindata.active_style_structs():${style_struct.ident},%endfor)})}/// Get the initial computed values.pubfninitial_values()->&'staticSelf{&*INITIAL_SERVO_VALUES}}#[cfg(feature = "servo")]implComputedValuesInner{/// Construct a `ComputedValuesInner` instance.pubfnnew(custom_properties:Option<Arc<::custom_properties::CustomPropertiesMap>>,writing_mode:WritingMode,font_size_keyword:Option<(longhands::font_size::KeywordSize,f32)>,flags:ComputedValueFlags,rules:Option<StrongRuleNode>,visited_style:Option<Arc<ComputedValues>>,%forstyle_structindata.active_style_structs():${style_struct.ident}:Arc<style_structs::${style_struct.name}>,%endfor)->Self{ComputedValuesInner{custom_properties:custom_properties,writing_mode:writing_mode,font_computation_data:FontComputationData::new(font_size_keyword),rules:rules,visited_style:visited_style,flags:flags,%forstyle_structindata.active_style_structs():${style_struct.ident}:${style_struct.ident},%endfor}}}#[cfg(feature = "servo")]implops::DerefforComputedValues{typeTarget=ComputedValuesInner;fnderef(&self)->&ComputedValuesInner{&self.inner}}#[cfg(feature = "servo")]implops::DerefMutforComputedValues{fnderef_mut(&mutself)->&mutComputedValuesInner{&mutself.inner}}#[cfg(feature = "servo")]implComputedValuesInner{%forstyle_structindata.active_style_structs():/// Clone the ${style_struct.name} struct.#[inline]pubfnclone_${style_struct.name_lower}(&self)->Arc<style_structs::${style_struct.name}>{self.${style_struct.ident}.clone()}/// Get a immutable reference to the ${style_struct.name} struct.#[inline]pubfnget_${style_struct.name_lower}(&self)->&style_structs::${style_struct.name}{&self.${style_struct.ident}}/// Gets an immutable reference to the refcounted value that wraps/// `${style_struct.name}`.pubfn${style_struct.name_lower}_arc(&self)->&Arc<style_structs::${style_struct.name}>{&self.${style_struct.ident}}/// Get a mutable reference to the ${style_struct.name} struct.#[inline]pubfnmutate_${style_struct.name_lower}(&mutself)->&mutstyle_structs::${style_struct.name}{Arc::make_mut(&mutself.${style_struct.ident})}%endfor/// Gets a reference to the rule node. Panic if no rule node exists.pubfnrules(&self)->&StrongRuleNode{self.rules.as_ref().unwrap()}/// Whether there is a visited style.pubfnhas_visited_style(&self)->bool{self.visited_style.is_some()}/// Gets a reference to the visited style, if any.pubfnget_visited_style(&self)->Option<&ComputedValues>{self.visited_style.as_ref().map(|x|&**x)}/// Gets a reference to the visited style. Panic if no visited style exists.pubfnvisited_style(&self)->&ComputedValues{self.get_visited_style().unwrap()}/// Clone the visited style. Used for inheriting parent styles in/// StyleBuilder::for_inheritance.pubfnclone_visited_style(&self)->Option<Arc<ComputedValues>>{self.visited_style.clone()}// Aah! The << in the return type below is not valid syntax, but we must// escape < that way for Mako./// Gets a reference to the custom properties map (if one exists).pubfnget_custom_properties(&self)->Option<<&::custom_properties::CustomPropertiesMap>{self.custom_properties.as_ref().map(|x|&**x)}/// Get the custom properties map if necessary.////// Cloning the Arc here is fine because it only happens in the case where/// we have custom properties, and those are both rare and expensive.pubfncustom_properties(&self)->Option<Arc<::custom_properties::CustomPropertiesMap>>{self.custom_properties.clone()}/// Whether this style has a -moz-binding value. This is always false for/// Servo for obvious reasons.pubfnhas_moz_binding(&self)->bool{false}/// Returns whether this style's display value is equal to contents.////// Since this isn't supported in Servo, this is always false for Servo.pubfnis_display_contents(&self)->bool{false}#[inline]/// Returns whether the "content" property for the given style is completely/// ineffective, and would yield an empty `::before` or `::after`/// pseudo-element.pubfnineffective_content_property(&self)->bool{useproperties::longhands::content::computed_value::T;matchself.get_counters().content{T::Normal|T::None=>true,T::Items(refitems)=>items.is_empty(),}}/// Whether the current style is multicolumn.#[inline]pubfnis_multicol(&self)->bool{letstyle=self.get_column();matchstyle.column_width{Either::First(_width)=>true,Either::Second(_auto)=>matchstyle.column_count{Either::First(_n)=>true,Either::Second(_auto)=>false,}}}/// Resolves the currentColor keyword.////// Any color value from computed values (except for the 'color' property/// itself) should go through this method.////// Usage example:/// let top_color = style.resolve_color(style.Border.border_top_color);#[inline]pubfnresolve_color(&self,color:computed::Color)->RGBA{color.to_rgba(self.get_color().color)}/// Get the logical computed inline size.#[inline]pubfncontent_inline_size(&self)->computed::LengthOrPercentageOrAuto{letposition_style=self.get_position();ifself.writing_mode.is_vertical(){position_style.height}else{position_style.width}}/// Get the logical computed block size.#[inline]pubfncontent_block_size(&self)->computed::LengthOrPercentageOrAuto{letposition_style=self.get_position();ifself.writing_mode.is_vertical(){position_style.width}else{position_style.height}}/// Get the logical computed min inline size.#[inline]pubfnmin_inline_size(&self)->computed::LengthOrPercentage{letposition_style=self.get_position();ifself.writing_mode.is_vertical(){position_style.min_height}else{position_style.min_width}}/// Get the logical computed min block size.#[inline]pubfnmin_block_size(&self)->computed::LengthOrPercentage{letposition_style=self.get_position();ifself.writing_mode.is_vertical(){position_style.min_width}else{position_style.min_height}}/// Get the logical computed max inline size.#[inline]pubfnmax_inline_size(&self)->computed::LengthOrPercentageOrNone{letposition_style=self.get_position();ifself.writing_mode.is_vertical(){position_style.max_height}else{position_style.max_width}}/// Get the logical computed max block size.#[inline]pubfnmax_block_size(&self)->computed::LengthOrPercentageOrNone{letposition_style=self.get_position();ifself.writing_mode.is_vertical(){position_style.max_width}else{position_style.max_height}}/// Get the logical computed padding for this writing mode.#[inline]pubfnlogical_padding(&self)->LogicalMargin<computed::LengthOrPercentage>{letpadding_style=self.get_padding();LogicalMargin::from_physical(self.writing_mode,SideOffsets2D::new(padding_style.padding_top.0,padding_style.padding_right.0,padding_style.padding_bottom.0,padding_style.padding_left.0,))}/// Get the logical border width#[inline]pubfnborder_width_for_writing_mode(&self,writing_mode:WritingMode)->LogicalMargin<Au>{letborder_style=self.get_border();LogicalMargin::from_physical(writing_mode,SideOffsets2D::new(border_style.border_top_width.0,border_style.border_right_width.0,border_style.border_bottom_width.0,border_style.border_left_width.0,))}/// Gets the logical computed border widths for this style.#[inline]pubfnlogical_border_width(&self)->LogicalMargin<Au>{self.border_width_for_writing_mode(self.writing_mode)}/// Gets the logical computed margin from this style.#[inline]pubfnlogical_margin(&self)->LogicalMargin<computed::LengthOrPercentageOrAuto>{letmargin_style=self.get_margin();LogicalMargin::from_physical(self.writing_mode,SideOffsets2D::new(margin_style.margin_top,margin_style.margin_right,margin_style.margin_bottom,margin_style.margin_left,))}/// Gets the logical position from this style.#[inline]pubfnlogical_position(&self)->LogicalMargin<computed::LengthOrPercentageOrAuto>{// FIXME(SimonSapin): should be the writing mode of the containing block, maybe?letposition_style=self.get_position();LogicalMargin::from_physical(self.writing_mode,SideOffsets2D::new(position_style.top,position_style.right,position_style.bottom,position_style.left,))}/// Return true if the effects force the transform style to be Flatpubfnoverrides_transform_style(&self)->bool{usecomputed_values::mix_blend_mode;leteffects=self.get_effects();// TODO(gw): Add clip-path, isolation, mask-image, mask-border-source when supported.effects.opacity<1.0||!effects.filter.0.is_empty()||!effects.clip.is_auto()||effects.mix_blend_mode!=mix_blend_mode::T::normal}/// https://drafts.csswg.org/css-transforms/#grouping-property-valuespubfnget_used_transform_style(&self)->computed_values::transform_style::T{usecomputed_values::transform_style;letbox_=self.get_box();ifself.overrides_transform_style(){transform_style::T::flat}else{// Return the computed value if not overridden by the above exceptionsbox_.transform_style}}/// Whether given this transform value, the compositor would require a/// layer.pubfntransform_requires_layer(&self)->bool{// Check if the transform matrix is 2D or 3DifletSome(reftransform_list)=self.get_box().transform.0{fortransformintransform_list{match*transform{computed_values::transform::ComputedOperation::Perspective(..)=>{returntrue;}computed_values::transform::ComputedOperation::Matrix(m)=>{// See http://dev.w3.org/csswg/css-transforms/#2d-matrixifm.m31!=0.0||m.m32!=0.0||m.m13!=0.0||m.m23!=0.0||m.m43!=0.0||m.m14!=0.0||m.m24!=0.0||m.m34!=0.0||m.m33!=1.0||m.m44!=1.0{returntrue;}}computed_values::transform::ComputedOperation::Translate(_,_,z)=>{ifz!=Au(0){returntrue;}}_=>{}}}}// Neither perspective nor transform presentfalse}/// Serializes the computed value of this property as a string.pubfncomputed_value_to_string(&self,property:PropertyDeclarationId)->String{matchproperty{%forstyle_structindata.active_style_structs():%forlonghandinstyle_struct.longhands:PropertyDeclarationId::Longhand(LonghandId::${longhand.camel_case})=>{self.${style_struct.ident}.${longhand.ident}.to_css_string()}%endfor%endforPropertyDeclarationId::Custom(name)=>{self.custom_properties.as_ref().and_then(|map|map.get_computed_value(name)).map(|value|value.to_css_string()).unwrap_or(String::new())}}}}/// Return a WritingMode bitflags from the relevant CSS properties.pubfnget_writing_mode(inheritedbox_style:&style_structs::InheritedBox)->WritingMode{uselogical_geometry;letmutflags=WritingMode::empty();matchinheritedbox_style.clone_direction(){computed_values::direction::T::ltr=>{},computed_values::direction::T::rtl=>{flags.insert(logical_geometry::FLAG_RTL);},}matchinheritedbox_style.clone_writing_mode(){computed_values::writing_mode::T::horizontal_tb=>{},computed_values::writing_mode::T::vertical_rl=>{flags.insert(logical_geometry::FLAG_VERTICAL);},computed_values::writing_mode::T::vertical_lr=>{flags.insert(logical_geometry::FLAG_VERTICAL);flags.insert(logical_geometry::FLAG_VERTICAL_LR);},%ifproduct=="gecko":computed_values::writing_mode::T::sideways_rl=>{flags.insert(logical_geometry::FLAG_VERTICAL);flags.insert(logical_geometry::FLAG_SIDEWAYS);},computed_values::writing_mode::T::sideways_lr=>{flags.insert(logical_geometry::FLAG_VERTICAL);flags.insert(logical_geometry::FLAG_VERTICAL_LR);flags.insert(logical_geometry::FLAG_LINE_INVERTED);flags.insert(logical_geometry::FLAG_SIDEWAYS);},%endif}%ifproduct=="gecko":// If FLAG_SIDEWAYS is already set, this means writing-mode is either// sideways-rl or sideways-lr, and for both of these values,// text-orientation has no effect.if!flags.intersects(logical_geometry::FLAG_SIDEWAYS){matchinheritedbox_style.clone_text_orientation(){computed_values::text_orientation::T::mixed=>{},computed_values::text_orientation::T::upright=>{flags.insert(logical_geometry::FLAG_UPRIGHT);},computed_values::text_orientation::T::sideways=>{flags.insert(logical_geometry::FLAG_SIDEWAYS);},}}%endifflags}%ifproduct=="gecko":pubuse::servo_arc::RawOffsetArcasBuilderArc;/// Clone an arc, returning a regular arcfnclone_arc<T:'static>(x:&BuilderArc<T>)->Arc<T>{Arc::from_raw_offset(x.clone())}%else:pubuse::servo_arc::ArcasBuilderArc;/// Clone an arc, returning a regular arcfnclone_arc<T:'static>(x:&BuilderArc<T>)->Arc<T>{x.clone()}%endif/// A reference to a style struct of the parent, or our own style struct.pubenumStyleStructRef<'a,T:'static>{/// A borrowed struct from the parent, for example, for inheriting style.Borrowed(&'aBuilderArc<T>),/// An owned struct, that we've already mutated.Owned(UniqueArc<T>),/// Temporarily vacated, will panic if accessedVacated,}impl<'a,T:'a>StyleStructRef<'a,T>whereT:Clone,{/// Ensure a mutable reference of this value exists, either cloning the/// borrowed value, or returning the owned one.pubfnmutate(&mutself)->&mutT{ifletStyleStructRef::Borrowed(v)=*self{*self=StyleStructRef::Owned(UniqueArc::new((**v).clone()));}match*self{StyleStructRef::Owned(refmutv)=>v,StyleStructRef::Borrowed(..)=>unreachable!(),StyleStructRef::Vacated=>panic!("Accessed vacated style struct")}}/// Extract a unique Arc from this struct, vacating it.////// The vacated state is a transient one, please put the Arc back/// when done via `put()`. This function is to be used to separate/// the struct being mutated from the computed contextpubfntake(&mutself)->UniqueArc<T>{usestd::mem::replace;letinner=replace(self,StyleStructRef::Vacated);matchinner{StyleStructRef::Owned(arc)=>arc,StyleStructRef::Borrowed(arc)=>UniqueArc::new((**arc).clone()),StyleStructRef::Vacated=>panic!("Accessed vacated style struct"),}}/// Replace vacated ref with an arcpubfnput(&mutself,arc:UniqueArc<T>){debug_assert!(matches!(*self,StyleStructRef::Vacated));*self=StyleStructRef::Owned(arc);}/// Get a mutable reference to the owned struct, or `None` if the struct/// hasn't been mutated.pubfnget_if_mutated(&mutself)->Option<<&mutT>{match*self{StyleStructRef::Owned(refmutv)=>Some(v),StyleStructRef::Borrowed(..)=>None,StyleStructRef::Vacated=>panic!("Accessed vacated style struct")}}/// Returns an `Arc` to the internal struct, constructing one if/// appropriate.pubfnbuild(self)->Arc<T>{matchself{StyleStructRef::Owned(v)=>v.shareable(),StyleStructRef::Borrowed(v)=>clone_arc(v),StyleStructRef::Vacated=>panic!("Accessed vacated style struct")}}}impl<'a,T:'a>ops::DerefforStyleStructRef<'a,T>{typeTarget=T;fnderef(&self)->&T{match*self{StyleStructRef::Owned(refv)=>&**v,StyleStructRef::Borrowed(v)=>&**v,StyleStructRef::Vacated=>panic!("Accessed vacated style struct")}}}/// A type used to compute a struct with minimal overhead.////// This allows holding references to the parent/default computed values without/// actually cloning them, until we either build the style, or mutate the/// inherited value.pubstructStyleBuilder<'a>{/// The device we're using to compute style.////// This provides access to viewport unit ratios, etc.pubdevice:&'aDevice,/// The style we're inheriting from.////// This is effectively/// `parent_style.unwrap_or(device.default_computed_values())`.inherited_style:&'aComputedValues,/// The style we're inheriting from for properties that don't inherit from/// ::first-line. This is the same as inherited_style, unless/// inherited_style is a ::first-line style.inherited_style_ignoring_first_line:&'aComputedValues,/// The style we're getting reset structs from.reset_style:&'aComputedValues,/// The style we're inheriting from explicitly, or none if we're the root of/// a subtree.parent_style:Option<<&'aComputedValues>,/// The rule node representing the ordered list of rules matched for this/// node.rules:Option<StrongRuleNode>,custom_properties:Option<Arc<::custom_properties::CustomPropertiesMap>>,/// The pseudo-element this style will represent.pseudo:Option<<&'aPseudoElement>,/// The writing mode flags.////// TODO(emilio): Make private.pubwriting_mode:WritingMode,/// The keyword behind the current font-size property, if any.pubfont_size_keyword:Option<(longhands::font_size::KeywordSize,f32)>,/// Flags for the computed value.pubflags:ComputedValueFlags,/// The element's style if visited, only computed if there's a relevant link/// for this element. A element's "relevant link" is the element being/// matched if it is a link or the nearest ancestor link.visited_style:Option<Arc<ComputedValues>>,%forstyle_structindata.active_style_structs():${style_struct.ident}:StyleStructRef<'a,style_structs::${style_struct.name}>,%endfor}impl<'a>StyleBuilder<'a>{/// Trivially construct a `StyleBuilder`.fnnew(device:&'aDevice,parent_style:Option<<&'aComputedValues>,parent_style_ignoring_first_line:Option<<&'aComputedValues>,pseudo:Option<<&'aPseudoElement>,cascade_flags:CascadeFlags,rules:Option<StrongRuleNode>,custom_properties:Option<Arc<::custom_properties::CustomPropertiesMap>>,writing_mode:WritingMode,font_size_keyword:Option<(longhands::font_size::KeywordSize,f32)>,flags:ComputedValueFlags,visited_style:Option<Arc<ComputedValues>>,)->Self{debug_assert_eq!(parent_style.is_some(),parent_style_ignoring_first_line.is_some());#[cfg(feature = "gecko")]debug_assert!(parent_style.is_none()||ptr::eq(parent_style.unwrap(),parent_style_ignoring_first_line.unwrap())||parent_style.unwrap().pseudo()==Some(PseudoElement::FirstLine));letreset_style=device.default_computed_values();letinherited_style=parent_style.unwrap_or(reset_style);letinherited_style_ignoring_first_line=parent_style_ignoring_first_line.unwrap_or(reset_style);// FIXME(bz): INHERIT_ALL seems like a fundamentally broken idea. I'm// 99% sure it should give incorrect behavior for table anonymous box// backgrounds, for example. This code doesn't attempt to make it play// nice with inherited_style_ignoring_first_line.letreset_style=ifcascade_flags.contains(INHERIT_ALL){inherited_style}else{reset_style};StyleBuilder{device,parent_style,inherited_style,inherited_style_ignoring_first_line,reset_style,pseudo,rules,custom_properties,writing_mode,font_size_keyword,flags,visited_style,%forstyle_structindata.active_style_structs():%ifstyle_struct.inherited:${style_struct.ident}:StyleStructRef::Borrowed(inherited_style.${style_struct.name_lower}_arc()),%else:${style_struct.ident}:StyleStructRef::Borrowed(reset_style.${style_struct.name_lower}_arc()),%endif%endfor}}/// Creates a StyleBuilder holding only references to the structs of `s`, in/// order to create a derived style.pubfnfor_derived_style(device:&'aDevice,style_to_derive_from:&'aComputedValues,parent_style:Option<<&'aComputedValues>,pseudo:Option<<&'aPseudoElement>,)->Self{letreset_style=device.default_computed_values();letinherited_style=parent_style.unwrap_or(reset_style);#[cfg(feature = "gecko")]debug_assert!(parent_style.is_none()||parent_style.unwrap().pseudo()!=Some(PseudoElement::FirstLine));StyleBuilder{device,parent_style,inherited_style,// None of our callers pass in ::first-line parent styles.inherited_style_ignoring_first_line:inherited_style,reset_style,pseudo,rules:None,// FIXME(emilio): Dubious...custom_properties:style_to_derive_from.custom_properties(),writing_mode:style_to_derive_from.writing_mode,font_size_keyword:style_to_derive_from.font_computation_data.font_size_keyword,flags:style_to_derive_from.flags,visited_style:style_to_derive_from.clone_visited_style(),%forstyle_structindata.active_style_structs():${style_struct.ident}:StyleStructRef::Borrowed(style_to_derive_from.${style_struct.name_lower}_arc()),%endfor}}%forpropertyindata.longhands:%ifproperty.ident!="font_size":/// Inherit `${property.ident}` from our parent style.#[allow(non_snake_case)]pubfninherit_${property.ident}(&mutself){letinherited_struct=%ifproperty.style_struct.inherited:self.inherited_style.get_${property.style_struct.name_lower}();%else:self.inherited_style_ignoring_first_line.get_${property.style_struct.name_lower}();%endifself.${property.style_struct.ident}.mutate().copy_${property.ident}_from(inherited_struct,%ifproperty.logical:self.writing_mode,%endif);}/// Reset `${property.ident}` to the initial value.#[allow(non_snake_case)]pubfnreset_${property.ident}(&mutself){letreset_struct=self.reset_style.get_${property.style_struct.name_lower}();self.${property.style_struct.ident}.mutate().reset_${property.ident}(reset_struct,%ifproperty.logical:self.writing_mode,%endif);}%ifnotproperty.is_vector:/// Set the `${property.ident}` to the computed value `value`.#[allow(non_snake_case)]pubfnset_${property.ident}(&mutself,value:longhands::${property.ident}::computed_value::T){self.${property.style_struct.ident}.mutate().set_${property.ident}(value,%ifproperty.logical:self.writing_mode,%elifproduct=="gecko"andproperty.identin["content","list_style_type"]:self.device,%endif);}%endif%endif%endfor/// Inherits style from the parent element, accounting for the default/// computed values that need to be provided as well.pubfnfor_inheritance(device:&'aDevice,parent:&'aComputedValues,pseudo:Option<<&'aPseudoElement>,)->Self{// FIXME(emilio): This Some(parent) here is inconsistent with what we// usually do if `parent` is the default computed values, but that's// fine, and we want to eventually get rid of it.Self::new(device,Some(parent),Some(parent),pseudo,CascadeFlags::empty(),/* rules = */None,parent.custom_properties(),parent.writing_mode,parent.font_computation_data.font_size_keyword,parent.flags,parent.clone_visited_style())}/// Returns whether we have a visited style.pubfnhas_visited_style(&self)->bool{self.visited_style.is_some()}/// Returns whether we're a pseudo-elements style.pubfnis_pseudo_element(&self)->bool{self.pseudo.map_or(false,|p|!p.is_anon_box())}/// Returns the style we're getting reset properties from.pubfndefault_style(&self)->&'aComputedValues{self.reset_style}%forstyle_structindata.active_style_structs():/// Gets an immutable view of the current `${style_struct.name}` style.pubfnget_${style_struct.name_lower}(&self)->&style_structs::${style_struct.name}{&self.${style_struct.ident}}/// Gets a mutable view of the current `${style_struct.name}` style.pubfnmutate_${style_struct.name_lower}(&mutself)->&mutstyle_structs::${style_struct.name}{self.${style_struct.ident}.mutate()}/// Gets a mutable view of the current `${style_struct.name}` style.pubfntake_${style_struct.name_lower}(&mutself)->UniqueArc<style_structs::${style_struct.name}>{self.${style_struct.ident}.take()}/// Gets a mutable view of the current `${style_struct.name}` style.pubfnput_${style_struct.name_lower}(&mutself,s:UniqueArc<style_structs::${style_struct.name}>){self.${style_struct.ident}.put(s)}/// Gets a mutable view of the current `${style_struct.name}` style,/// only if it's been mutated before.pubfnget_${style_struct.name_lower}_if_mutated(&mutself)->Option<<&mutstyle_structs::${style_struct.name}>{self.${style_struct.ident}.get_if_mutated()}/// Reset the current `${style_struct.name}` style to its default value.pubfnreset_${style_struct.name_lower}_struct(&mutself){self.${style_struct.ident}=StyleStructRef::Borrowed(self.reset_style.${style_struct.name_lower}_arc());}%endfor/// Returns whether this computed style represents a floated object.pubfnfloated(&self)->bool{self.get_box().clone_float()!=longhands::float::computed_value::T::none}/// Returns whether this computed style represents an out of flow-positioned/// object.pubfnout_of_flow_positioned(&self)->bool{useproperties::longhands::position::computed_value::Tasposition;matches!(self.get_box().clone_position(),position::absolute|position::fixed)}/// Whether this style has a top-layer style. That's implemented in Gecko/// via the -moz-top-layer property, but servo doesn't have any concept of a/// top layer (yet, it's needed for fullscreen).#[cfg(feature = "servo")]pubfnin_top_layer(&self)->bool{false}/// Whether this style has a top-layer style.#[cfg(feature = "gecko")]pubfnin_top_layer(&self)->bool{matches!(self.get_box().clone__moz_top_layer(),longhands::_moz_top_layer::computed_value::T::top)}/// Turns this `StyleBuilder` into a proper `ComputedValues` instance.pubfnbuild(self)->Arc<ComputedValues>{ComputedValues::new(self.device,self.parent_style,self.pseudo,self.custom_properties,self.writing_mode,self.font_size_keyword,self.flags,self.rules,self.visited_style,%forstyle_structindata.active_style_structs():self.${style_struct.ident}.build(),%endfor)}/// Get the custom properties map if necessary.////// Cloning the Arc here is fine because it only happens in the case where/// we have custom properties, and those are both rare and expensive.fncustom_properties(&self)->Option<Arc<::custom_properties::CustomPropertiesMap>>{self.custom_properties.clone()}/// Access to various information about our inherited styles. We don't/// expose an inherited ComputedValues directly, because in the/// ::first-line case some of the inherited information needs to come from/// one ComputedValues instance and some from a different one./// Inherited font bits.pubfninherited_font_computation_data(&self)->&FontComputationData{&self.inherited_style.font_computation_data}/// Inherited writing-mode.pubfninherited_writing_mode(&self)->&WritingMode{&self.inherited_style.writing_mode}/// Inherited style flags.pubfninherited_flags(&self)->&ComputedValueFlags{&self.inherited_style.flags}/// And access to inherited style structs.%forstyle_structindata.active_style_structs():/// Gets our inherited `${style_struct.name}`. We don't name these/// accessors `inherited_${style_struct.name_lower}` because we already/// have things like "box" vs "inherited_box" as struct names. Do the/// next-best thing and call them `parent_${style_struct.name_lower}`/// instead.pubfnget_parent_${style_struct.name_lower}(&self)->&style_structs::${style_struct.name}{%ifstyle_struct.inherited:self.inherited_style.get_${style_struct.name_lower}()%else:self.inherited_style_ignoring_first_line.get_${style_struct.name_lower}()%endif}%endfor}#[cfg(feature = "servo")]pubuseself::lazy_static_module::INITIAL_SERVO_VALUES;// Use a module to work around #[cfg] on lazy_static! not being applied to every generated item.#[cfg(feature = "servo")]#[allow(missing_docs)]modlazy_static_module{uselogical_geometry::WritingMode;useservo_arc::Arc;usesuper::{ComputedValues,ComputedValuesInner,longhands,style_structs,FontComputationData};usesuper::computed_value_flags::ComputedValueFlags;/// The initial values for all style structs as defined by the specification.lazy_static!{pubstaticrefINITIAL_SERVO_VALUES:ComputedValues=ComputedValues{inner:ComputedValuesInner{%forstyle_structindata.active_style_structs():${style_struct.ident}:Arc::new(style_structs::${style_struct.name}{%forlonghandinstyle_struct.longhands:${longhand.ident}:longhands::${longhand.ident}::get_initial_value(),%endfor%ifstyle_struct.name=="Font":hash:0,%endif}),%endforcustom_properties:None,writing_mode:WritingMode::empty(),font_computation_data:FontComputationData::default_values(),rules:None,visited_style:None,flags:ComputedValueFlags::empty(),}};}}/// A per-longhand function that performs the CSS cascade for that longhand.pubtypeCascadePropertyFn=extern"Rust"fn(declaration:&PropertyDeclaration,context:&mutcomputed::Context,cascade_info:&mutOption<<&mutCascadeInfo>);/// A per-longhand array of functions to perform the CSS cascade on each of/// them, effectively doing virtual dispatch.staticCASCADE_PROPERTY:[CascadePropertyFn;${len(data.longhands)}]=[%forpropertyindata.longhands:longhands::${property.ident}::cascade_property,%endfor];bitflags!{/// A set of flags to tweak the behavior of the `cascade` function.pubflagsCascadeFlags:u8{/// Whether to inherit all styles from the parent. If this flag is not/// present, non-inherited styles are reset to their initial values.constINHERIT_ALL=1,/// Whether to skip any display style fixup for root element, flex/grid/// item, and ruby descendants.constSKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP=1<<1,/// Whether to only cascade properties that are visited dependent.constVISITED_DEPENDENT_ONLY=1<<2,/// Whether the given element we're styling is the document element,/// that is, matches :root.////// Not set for native anonymous content since some NAC form their own/// root, but share the device.////// This affects some style adjustments, like blockification, and means/// that it may affect global state, like the Device's root font-size.constIS_ROOT_ELEMENT=1<<3,/// Whether to convert display:contents into display:inline. This/// is used by Gecko to prevent display:contents on generated/// content.constPROHIBIT_DISPLAY_CONTENTS=1<<4,/// Whether we're styling the ::-moz-fieldset-content anonymous box.constIS_FIELDSET_CONTENT=1<<5,/// Whether we're computing the style of a link, either visited or/// unvisited.constIS_LINK=1<<6,/// Whether we're computing the style of a link element that happens to/// be visited.constIS_VISITED_LINK=1<<7,}}/// Performs the CSS cascade, computing new styles for an element from its parent style.////// The arguments are:////// * `device`: Used to get the initial viewport and other external state.////// * `rule_node`: The rule node in the tree that represent the CSS rules that/// matched.////// * `parent_style`: The parent style, if applicable; if `None`, this is the root node.////// Returns the computed values./// * `flags`: Various flags.///pubfncascade(device:&Device,pseudo:Option<<&PseudoElement>,rule_node:&StrongRuleNode,guards:&StylesheetGuards,parent_style:Option<<&ComputedValues>,parent_style_ignoring_first_line:Option<<&ComputedValues>,layout_parent_style:Option<<&ComputedValues>,visited_style:Option<Arc<ComputedValues>>,cascade_info:Option<<&mutCascadeInfo>,font_metrics_provider:&FontMetricsProvider,flags:CascadeFlags,quirks_mode:QuirksMode)->Arc<ComputedValues>{debug_assert_eq!(parent_style.is_some(),parent_style_ignoring_first_line.is_some());#[cfg(feature = "gecko")]debug_assert!(parent_style.is_none()||ptr::eq(parent_style.unwrap(),parent_style_ignoring_first_line.unwrap())||parent_style.unwrap().pseudo()==Some(PseudoElement::FirstLine));letiter_declarations=||{rule_node.self_and_ancestors().flat_map(|node|{letcascade_level=node.cascade_level();letsource=node.style_source();letdeclarations=ifsource.is_some(){source.read(cascade_level.guard(guards)).declarations()}else{// The root node has no style source.&[]};letnode_importance=node.importance();letproperty_restriction=pseudo.and_then(|p|p.property_restriction());declarations.iter()// Yield declarations later in source order (with more precedence) first..rev().filter_map(move|&(refdeclaration,declaration_importance)|{ifletSome(property_restriction)=property_restriction{// declaration.id() is either a longhand or a custom// property. Custom properties are always allowed, but// longhands are only allowed if they have our// property_restriction flag set.ifletPropertyDeclarationId::Longhand(id)=declaration.id(){if!id.flags().contains(property_restriction){returnNone}}}ifdeclaration_importance==node_importance{Some((declaration,cascade_level))}else{None}})})};apply_declarations(device,pseudo,rule_node,iter_declarations,parent_style,parent_style_ignoring_first_line,layout_parent_style,visited_style,cascade_info,font_metrics_provider,flags,quirks_mode,)}/// NOTE: This function expects the declaration with more priority to appear/// first.#[allow(unused_mut)]// conditionally compiled code for "position"pubfnapply_declarations<'a,F,I>(device:&Device,pseudo:Option<<&PseudoElement>,rules:&StrongRuleNode,iter_declarations:F,parent_style:Option<<&ComputedValues>,parent_style_ignoring_first_line:Option<<&ComputedValues>,layout_parent_style:Option<<&ComputedValues>,visited_style:Option<Arc<ComputedValues>>,mutcascade_info:Option<<&mutCascadeInfo>,font_metrics_provider:&FontMetricsProvider,flags:CascadeFlags,quirks_mode:QuirksMode,)->Arc<ComputedValues>whereF:Fn()->I,I:Iterator<Item=(&'aPropertyDeclaration,CascadeLevel)>,{debug_assert!(layout_parent_style.is_none()||parent_style.is_some());debug_assert_eq!(parent_style.is_some(),parent_style_ignoring_first_line.is_some());#[cfg(feature = "gecko")]debug_assert!(parent_style.is_none()||ptr::eq(parent_style.unwrap(),parent_style_ignoring_first_line.unwrap())||parent_style.unwrap().pseudo()==Some(PseudoElement::FirstLine));let(inherited_style,layout_parent_style)=matchparent_style{Some(parent_style)=>{(parent_style,layout_parent_style.unwrap_or(parent_style))},None=>{(device.default_computed_values(),device.default_computed_values())}};letinherited_custom_properties=inherited_style.custom_properties();letmutcustom_properties=None;letmutseen_custom=HashSet::new();for(declaration,_cascade_level)initer_declarations(){ifletPropertyDeclaration::Custom(refname,refvalue)=*declaration{::custom_properties::cascade(&mutcustom_properties,&inherited_custom_properties,&mutseen_custom,name,value.borrow());}}letcustom_properties=::custom_properties::finish_cascade(custom_properties,&inherited_custom_properties);letmutcontext=computed::Context{is_root_element:flags.contains(IS_ROOT_ELEMENT),// We'd really like to own the rules here to avoid refcount traffic, but// animation's usage of `apply_declarations` make this tricky. See bug// 1375525.builder:StyleBuilder::new(device,parent_style,parent_style_ignoring_first_line,pseudo,flags,Some(rules.clone()),custom_properties,WritingMode::empty(),inherited_style.font_computation_data.font_size_keyword,ComputedValueFlags::empty(),visited_style,),font_metrics_provider:font_metrics_provider,cached_system_font:None,in_media_query:false,quirks_mode:quirks_mode,for_smil_animation:false,};letignore_colors=!device.use_document_colors();letdefault_background_color_decl=ifignore_colors{letcolor=device.default_background_color();Some(PropertyDeclaration::BackgroundColor(color.into()))}else{None};// Set computed values, overwriting earlier declarations for the same// property.letmutseen=LonghandIdSet::new();// Declaration blocks are stored in increasing precedence order, we want// them in decreasing order here.//// We could (and used to) use a pattern match here, but that bloats this// function to over 100K of compiled code!//// To improve i-cache behavior, we outline the individual functions and use// virtual dispatch instead.%forcategory_to_cascade_nowin["early","other"]:%ifcategory_to_cascade_now=="early":// Pull these out so that we can compute them in a specific order// without introducing more iterations.letmutfont_size=None;letmutfont_family=None;%endiffor(declaration,cascade_level)initer_declarations(){letmutdeclaration=match*declaration{PropertyDeclaration::WithVariables(id,refunparsed)=>{Cow::Owned(unparsed.substitute_variables(id,&context.builder.custom_properties,context.quirks_mode))}refd=>Cow::Borrowed(d)};letlonghand_id=matchdeclaration.id(){PropertyDeclarationId::Longhand(id)=>id,PropertyDeclarationId::Custom(..)=>continue,};// Only a few properties are allowed to depend on the visited state// of links. When cascading visited styles, we can save time by// only processing these properties.ifflags.contains(VISITED_DEPENDENT_ONLY)&&!longhand_id.is_visited_dependent(){continue}// When document colors are disabled, skip properties that are// marked as ignored in that mode, if they come from a UA or// user style sheet.ifignore_colors&&longhand_id.is_ignored_when_document_colors_disabled()&&!matches!(cascade_level,CascadeLevel::UANormal|CascadeLevel::UserNormal|CascadeLevel::UserImportant|CascadeLevel::UAImportant){letnon_transparent_background=match*declaration{PropertyDeclaration::BackgroundColor(refcolor)=>{// Treat background-color a bit differently. If the specified// color is anything other than a fully transparent color, convert// it into the Device's default background color.color.is_non_transparent()}_=>continue};// FIXME: moving this out of `match` is a work around for borrows being lexical.ifnon_transparent_background{declaration=Cow::Borrowed(default_background_color_decl.as_ref().unwrap());}}if%ifcategory_to_cascade_now=="early":!%endiflonghand_id.is_early_property(){continue}<%maybe_to_physical=".to_physical(writing_mode)"ifcategory_to_cascade_now!="early"else""%>letphysical_longhand_id=longhand_id${maybe_to_physical};ifseen.contains(physical_longhand_id){continue}seen.insert(physical_longhand_id);%ifcategory_to_cascade_now=="early":ifLonghandId::FontSize==longhand_id{font_size=Some(declaration.clone());continue;}ifLonghandId::FontFamily==longhand_id{font_family=Some(declaration.clone());continue;}%endifletdiscriminant=longhand_idasusize;(CASCADE_PROPERTY[discriminant])(&*declaration,&mutcontext,&mutcascade_info);}%ifcategory_to_cascade_now=="early":letwriting_mode=get_writing_mode(context.builder.get_inheritedbox());context.builder.writing_mode=writing_mode;letmut_skip_font_family=false;%ifproduct=="gecko":// <svg:text> is not affected by text zoom, and it uses a preshint to// disable it. We fix up the struct when this happens by unzooming// its contained font values, which will have been zoomed in the parentifseen.contains(LonghandId::XTextZoom){letzoom=context.builder.get_font().gecko().mAllowZoom;letparent_zoom=context.style().get_parent_font().gecko().mAllowZoom;ifzoom!=parent_zoom{debug_assert!(!zoom,"We only ever disable text zoom (in svg:text), never enable it");// can't borrow both device and font, use the take/put machineryletmutfont=context.builder.take_font();font.unzoom_fonts(context.device());context.builder.put_font(font);}}// Whenever a single generic value is specified, gecko will do a bunch of// recalculation walking up the rule tree, including handling the font-size stuff.// It basically repopulates the font struct with the default font for a given// generic and language. We handle the font-size stuff separately, so this boils// down to just copying over the font-family lists (no other aspect of the default// font can be configured).ifseen.contains(LonghandId::XLang)||font_family.is_some(){// if just the language changed, the inherited generic is all we needletmutgeneric=inherited_style.get_font().gecko().mGenericID;ifletSome(refdeclaration)=font_family{ifletPropertyDeclaration::FontFamily(reffam)=**declaration{ifletSome(id)=fam.single_generic(){generic=id;// In case of a specified font family with a single generic, we will// end up setting font family below, but its value would get// overwritten later in the pipeline when cascading.//// We instead skip cascading font-family in that case.//// In case of the language changing, we wish for a specified font-// family to override this, so we do not skip cascading then._skip_font_family=true;}}}// In case of just the language changing, the parent could have had no generic,// which Gecko just does regular cascading with. Do the same.// This can only happen in the case where the language changed but the family did notifgeneric!=structs::kGenericFont_NONE{letpres_context=context.builder.device.pres_context();letgecko_font=context.builder.mutate_font().gecko_mut();gecko_font.mGenericID=generic;unsafe{bindings::Gecko_nsStyleFont_PrefillDefaultForGeneric(gecko_font,pres_context,generic,);}}}%endif// It is important that font_size is computed before// the late properties (for em units), but after font-family// (for the base-font-size dependence for default and keyword font-sizes)// Additionally, when we support system fonts they will have to be// computed early, and *before* font_family, so I'm including// font_family here preemptively instead of keeping it within// the early properties.//// To avoid an extra iteration, we just pull out the property// during the early iteration and cascade them in order// after it.if!_skip_font_family{ifletSome(refdeclaration)=font_family{letdiscriminant=LonghandId::FontFamilyasusize;(CASCADE_PROPERTY[discriminant])(declaration,&mutcontext,&mutcascade_info);%ifproduct=="gecko":letdevice=context.builder.device;context.builder.mutate_font().fixup_none_generic(device);%endif}}ifletSome(refdeclaration)=font_size{letdiscriminant=LonghandId::FontSizeasusize;(CASCADE_PROPERTY[discriminant])(declaration,&mutcontext,&mutcascade_info);%ifproduct=="gecko":// Font size must be explicitly inherited to handle lang changes and// scriptlevel changes.}elseifseen.contains(LonghandId::XLang)||seen.contains(LonghandId::MozScriptLevel)||seen.contains(LonghandId::MozMinFontSizeRatio)||font_family.is_some(){letdiscriminant=LonghandId::FontSizeasusize;letsize=PropertyDeclaration::CSSWideKeyword(LonghandId::FontSize,CSSWideKeyword::Inherit);(CASCADE_PROPERTY[discriminant])(&size,&mutcontext,&mutcascade_info);%endif}%endif%endforletmutbuilder=context.builder;{StyleAdjuster::new(&mutbuilder).adjust(layout_parent_style,flags);}%ifproduct=="gecko":ifletSome(refmutbg)=builder.get_background_if_mutated(){bg.fill_arrays();}ifletSome(refmutsvg)=builder.get_svg_if_mutated(){svg.fill_arrays();}%endif%ifproduct=="servo":ifseen.contains(LonghandId::FontStyle)||seen.contains(LonghandId::FontWeight)||seen.contains(LonghandId::FontStretch)||seen.contains(LonghandId::FontFamily){builder.mutate_font().compute_font_hash();}%endifbuilder.build()}/// See StyleAdjuster::adjust_for_border_width.pubfnadjust_border_width(style:&mutStyleBuilder){%forsidein["top","right","bottom","left"]:// Like calling to_computed_value, which wouldn't type check.ifstyle.get_border().clone_border_${side}_style().none_or_hidden()&&style.get_border().border_${side}_has_nonzero_width(){style.set_border_${side}_width(NonNegativeAu::zero());}%endfor}/// Adjusts borders as appropriate to account for a fragment's status as the/// first or last fragment within the range of an element.////// Specifically, this function sets border widths to zero on the sides for/// which the fragment is not outermost.#[cfg(feature = "servo")]#[inline]pubfnmodify_border_style_for_inline_sides(style:&mutArc<ComputedValues>,is_first_fragment_of_element:bool,is_last_fragment_of_element:bool){fnmodify_side(style:&mutArc<ComputedValues>,side:PhysicalSide){{letborder=&style.border;letcurrent_style=matchside{PhysicalSide::Left=>(border.border_left_width,border.border_left_style),PhysicalSide::Right=>(border.border_right_width,border.border_right_style),PhysicalSide::Top=>(border.border_top_width,border.border_top_style),PhysicalSide::Bottom=>(border.border_bottom_width,border.border_bottom_style),};ifcurrent_style==(NonNegativeAu::zero(),BorderStyle::none){return;}}letmutstyle=Arc::make_mut(style);letborder=Arc::make_mut(&mutstyle.border);matchside{PhysicalSide::Left=>{border.border_left_width=NonNegativeAu::zero();border.border_left_style=BorderStyle::none;}PhysicalSide::Right=>{border.border_right_width=NonNegativeAu::zero();border.border_right_style=BorderStyle::none;}PhysicalSide::Bottom=>{border.border_bottom_width=NonNegativeAu::zero();border.border_bottom_style=BorderStyle::none;}PhysicalSide::Top=>{border.border_top_width=NonNegativeAu::zero();border.border_top_style=BorderStyle::none;}}}if!is_first_fragment_of_element{letside=style.writing_mode.inline_start_physical_side();modify_side(style,side)}if!is_last_fragment_of_element{letside=style.writing_mode.inline_end_physical_side();modify_side(style,side)}}#[macro_export]macro_rules!css_properties_accessors{($macro_name:ident)=>{$macro_name!{%forkind,propsin[("Longhand",data.longhands),("Shorthand",data.shorthands)]:%forpropertyinprops:%ifnotproperty.derived_fromandnotproperty.internal:%fornamein[property.name]+property.alias:%if'-'inname:[${to_rust_ident(name).capitalize()},Set${to_rust_ident(name).capitalize()},PropertyId::${kind}(${kind}Id::${property.camel_case})],%endif[${to_camel_case(name)},Set${to_camel_case(name)},PropertyId::${kind}(${kind}Id::${property.camel_case})],%endfor%endif%endfor%endfor}}}#[macro_export]macro_rules!longhand_properties_idents{($macro_name:ident)=>{$macro_name!{%forpropertyindata.longhands:{${property.ident},${"true"ifproperty.boxedelse"false"}}%endfor}}}