diff --git a/style/properties/helpers/animated_properties.mako.rs b/style/properties/helpers/animated_properties.mako.rs index 7cf2149f8a..92410c0ab1 100644 --- a/style/properties/helpers/animated_properties.mako.rs +++ b/style/properties/helpers/animated_properties.mako.rs @@ -216,40 +216,63 @@ impl AnimationValue { use super::PropertyDeclarationVariantRepr; - match *self { - <% keyfunc = lambda x: (x.base_type(), x.specified_type(), x.boxed, x.animation_type != "discrete") %> - % for (ty, specified, boxed, to_animated), props in groupby(animated, key=keyfunc): - <% props = list(props) %> - ${" |\n".join("{}(ref value)".format(prop.camel_case) for prop in props)} => { - % if to_animated: - let value = ToAnimatedValue::from_animated_value(value.clone()); - % endif - let value = ${ty}::from_computed_value(&value); - % if boxed: - let value = Box::new(value); - % endif - % if len(props) == 1: - PropertyDeclaration::${props[0].camel_case}(value) - % else: - unsafe { - let mut out = mem::MaybeUninit::uninit(); - ptr::write( - out.as_mut_ptr() as *mut PropertyDeclarationVariantRepr<${specified}>, - PropertyDeclarationVariantRepr { - tag: *(self as *const _ as *const u16), - value, - }, - ); - out.assume_init() - } - % endif + <% + keyfunc = lambda x: (x.base_type(), x.specified_type(), x.boxed, x.animation_type != "discrete") + uncompute_group = {} + for key, props in groupby(animated, key=keyfunc): + props = list(props) + for p in props: + uncompute_group[p.ident] = (key, props) + %> + type UncomputeFn = fn(&AnimationValue) -> PropertyDeclaration; + fn uncompute_void(_: &AnimationValue) -> PropertyDeclaration { + unsafe { debug_unreachable!() } + } + % for prop in animated: + <% (ty, specified, boxed, to_animated), props = uncompute_group[prop.ident] %> + #[allow(non_snake_case)] + fn uncompute_${prop.ident}(v: &AnimationValue) -> PropertyDeclaration { + let AnimationValue::${prop.camel_case}(ref value) = *v else { + unsafe { debug_unreachable!() } + }; + % if to_animated: + let value = ToAnimatedValue::from_animated_value(value.clone()); + % endif + let value = ${ty}::from_computed_value(&value); + % if boxed: + let value = Box::new(value); + % endif + % if len(props) == 1: + PropertyDeclaration::${prop.camel_case}(value) + % else: + unsafe { + let mut out = mem::MaybeUninit::uninit(); + ptr::write( + out.as_mut_ptr() as *mut PropertyDeclarationVariantRepr<${specified}>, + PropertyDeclarationVariantRepr { + tag: *(v as *const _ as *const u16), + value, + }, + ); + out.assume_init() } + % endif + } + % endfor + static UNCOMPUTE: [UncomputeFn; crate::properties::property_counts::LONGHANDS] = [ + % for prop in data.longhands: + % if prop.animatable and not prop.logical: + uncompute_${prop.ident}, + % else: + uncompute_void, + % endif % endfor - ${" |\n".join("{}(void)".format(prop.camel_case) for prop in unanimated)} => { - void::unreachable(void) - }, - Custom(ref animated_value) => animated_value.to_declaration(), + ]; + if let Custom(ref animated_value) = *self { + return animated_value.to_declaration(); } + let tag = unsafe { *(self as *const _ as *const u16) }; + UNCOMPUTE[tag as usize](self) } /// Construct an AnimationValue from a property declaration. @@ -260,8 +283,6 @@ impl AnimationValue { initial: &ComputedValues, attribute_tracker: &mut AttributeTracker, ) -> Option { - use super::PropertyDeclarationVariantRepr; - <% keyfunc = lambda x: ( x.specified_type(), @@ -273,100 +294,153 @@ impl AnimationValue { ) %> - let animatable = match *decl { - % for (specified_ty, ty, boxed, to_animated, inherit, system), props in groupby(animated_with_logical, key=keyfunc): - ${" |\n".join("PropertyDeclaration::{}(ref value)".format(prop.camel_case) for prop in props)} => { - let decl_repr = unsafe { - &*(decl as *const _ as *const PropertyDeclarationVariantRepr<${specified_ty}>) - }; - let longhand_id = unsafe { - *(&decl_repr.tag as *const u16 as *const LonghandId) - }; - context.for_non_inherited_property = ${"false" if inherit else "true"}; - % if system: - if let Some(sf) = value.get_system() { - gecko::system_font::resolve_system_font(sf, context) - } - % endif - % if boxed: - let value = (**value).to_computed_value(context); - % else: - let value = value.to_computed_value(context); + <% + from_decl_group = {} + for key, props in groupby(animated_with_logical, key=keyfunc): + props = list(props) + for p in props: + from_decl_group[p.ident] = key + %> + type FromDeclFn = fn( + &PropertyDeclaration, + &mut Context, + &ComputedValues, + ) -> Option; + fn from_decl_unanimatable( + _: &PropertyDeclaration, + _: &mut Context, + _: &ComputedValues, + ) -> Option { + // non animatable properties will get included because of shorthands. ignore. + None + } + % for prop in animated_with_logical: + <% specified_ty, ty, boxed, to_animated, inherit, system = from_decl_group[prop.ident] %> + #[allow(non_snake_case)] + fn from_decl_${prop.ident}( + decl: &PropertyDeclaration, + context: &mut Context, + style: &ComputedValues, + ) -> Option { + let PropertyDeclaration::${prop.camel_case}(ref value) = *decl else { + unsafe { debug_unreachable!() } + }; + let _ = style; + context.for_non_inherited_property = ${"false" if inherit else "true"}; + % if system: + if let Some(sf) = value.get_system() { + gecko::system_font::resolve_system_font(sf, context) + } + % endif + % if boxed: + let value = (**value).to_computed_value(context); + % else: + let value = value.to_computed_value(context); + % endif + % if to_animated: + let value = value.to_animated_value(&crate::values::animated::Context { style }); + % endif + + Some(unsafe { + let mut out = mem::MaybeUninit::uninit(); + ptr::write( + out.as_mut_ptr() as *mut AnimationValueVariantRepr<${ty}>, + AnimationValueVariantRepr { + tag: LonghandId::${prop.camel_case}.to_physical(context.builder.writing_mode) as u16, + value, + }, + ); + out.assume_init() + }) + } + % endfor + static FROM_DECL: [FromDeclFn; crate::properties::property_counts::LONGHANDS] = [ + % for prop in data.longhands: + % if prop.animatable: + from_decl_${prop.ident}, + % else: + from_decl_unanimatable, + % endif + % endfor + ]; + + type FromKeywordFn = fn( + CSSWideKeyword, + &mut Context, + &ComputedValues, + &ComputedValues, + ) -> Option; + fn from_keyword_unanimatable( + _: CSSWideKeyword, + _: &mut Context, + _: &ComputedValues, + _: &ComputedValues, + ) -> Option { + None + } + % for prop in data.longhands: + % if prop.animatable and not prop.logical: + #[allow(non_snake_case)] + fn from_keyword_${prop.ident}( + keyword: CSSWideKeyword, + context: &mut Context, + style: &ComputedValues, + initial: &ComputedValues, + ) -> Option { + let _ = style; + // FIXME(emilio, bug 1533327): I think revert (and + // revert-layer) handling is not fine here, but what to + // do instead? + // + // Seems we'd need the computed value as if it was + // revert, somehow. Treating it as `unset` seems fine + // for now... + let style_struct = match keyword { + % if not prop.style_struct.inherited: + CSSWideKeyword::Revert | + CSSWideKeyword::RevertRule | + CSSWideKeyword::RevertLayer | + CSSWideKeyword::Unset | % endif - % if to_animated: - let value = value.to_animated_value(&crate::values::animated::Context { style }); + CSSWideKeyword::Initial => { + initial.get_${prop.style_struct.name_lower}() + }, + % if prop.style_struct.inherited: + CSSWideKeyword::Revert | + CSSWideKeyword::RevertRule | + CSSWideKeyword::RevertLayer | + CSSWideKeyword::Unset | % endif + CSSWideKeyword::Inherit => { + context.builder + .get_parent_${prop.style_struct.name_lower}() + }, + }; + let computed = style_struct.clone_${prop.ident}(); - unsafe { - let mut out = mem::MaybeUninit::uninit(); - ptr::write( - out.as_mut_ptr() as *mut AnimationValueVariantRepr<${ty}>, - AnimationValueVariantRepr { - tag: longhand_id.to_physical(context.builder.writing_mode) as u16, - value, - }, - ); - out.assume_init() - } - } + % if prop.animation_type != "discrete": + let computed = computed.to_animated_value(&crate::values::animated::Context { + style + }); + % endif + Some(AnimationValue::${prop.camel_case}(computed)) + } + % endif + % endfor + static FROM_KEYWORD: [FromKeywordFn; crate::properties::property_counts::LONGHANDS] = [ + % for prop in data.longhands: + % if prop.animatable and not prop.logical: + from_keyword_${prop.ident}, + % else: + from_keyword_unanimatable, + % endif % endfor + ]; + + let animatable = match *decl { PropertyDeclaration::CSSWideKeyword(ref declaration) => { - match declaration.id.to_physical(context.builder.writing_mode) { - // We put all the animatable properties first in the hopes - // that it might increase match locality. - % for prop in data.longhands: - % if prop.animatable and not prop.logical: - LonghandId::${prop.camel_case} => { - // FIXME(emilio, bug 1533327): I think revert (and - // revert-layer) handling is not fine here, but what to - // do instead? - // - // Seems we'd need the computed value as if it was - // revert, somehow. Treating it as `unset` seems fine - // for now... - let style_struct = match declaration.keyword { - % if not prop.style_struct.inherited: - CSSWideKeyword::Revert | - CSSWideKeyword::RevertRule | - CSSWideKeyword::RevertLayer | - CSSWideKeyword::Unset | - % endif - CSSWideKeyword::Initial => { - initial.get_${prop.style_struct.name_lower}() - }, - % if prop.style_struct.inherited: - CSSWideKeyword::Revert | - CSSWideKeyword::RevertRule | - CSSWideKeyword::RevertLayer | - CSSWideKeyword::Unset | - % endif - CSSWideKeyword::Inherit => { - context.builder - .get_parent_${prop.style_struct.name_lower}() - }, - }; - let computed = style_struct - % if prop.logical: - .clone_${prop.ident}(context.builder.writing_mode); - % else: - .clone_${prop.ident}(); - % endif - - % if prop.animation_type != "discrete": - let computed = computed.to_animated_value(&crate::values::animated::Context { - style - }); - % endif - AnimationValue::${prop.camel_case}(computed) - }, - % endif - % endfor - % for prop in data.longhands: - % if not prop.animatable or prop.logical: - LonghandId::${prop.camel_case} => return None, - % endif - % endfor - } + let id = declaration.id.to_physical(context.builder.writing_mode); + return FROM_KEYWORD[id as usize](declaration.keyword, context, style, initial); }, PropertyDeclaration::WithVariables(ref declaration) => { let mut cache = Default::default(); @@ -400,7 +474,14 @@ impl AnimationValue { context, )?) }, - _ => return None // non animatable properties will get included because of shorthands. ignore. + _ => { + let tag = unsafe { *(decl as *const _ as *const u16) }; + if (tag as usize) < crate::properties::property_counts::LONGHANDS { + return FROM_DECL[tag as usize](decl, context, style); + } + // non animatable properties will get included because of shorthands. ignore. + return None; + } }; Some(animatable) } @@ -428,14 +509,28 @@ impl AnimationValue { } }; - match longhand { + type IsDifferentFn = fn(&ComputedValues, &ComputedValues) -> bool; + fn is_different_unanimatable(_: &ComputedValues, _: &ComputedValues) -> bool { + false + } + % for prop in data.longhands: + % if prop.animatable and not prop.logical: + #[allow(non_snake_case)] + fn is_different_${prop.ident}(before: &ComputedValues, after: &ComputedValues) -> bool { + !before.${prop.ident}_equals(after) + } + % endif + % endfor + static IS_DIFFERENT: [IsDifferentFn; crate::properties::property_counts::LONGHANDS] = [ % for prop in data.longhands: % if prop.animatable and not prop.logical: - LonghandId::${prop.camel_case} => !before.${prop.ident}_equals(after), + is_different_${prop.ident}, + % else: + is_different_unanimatable, % endif % endfor - _ => false, - } + ]; + IS_DIFFERENT[longhand as usize](before, after) } /// Get an AnimationValue for an declaration id from a given computed values. @@ -455,23 +550,35 @@ impl AnimationValue { } }; - Some(match property { + type FromComputedFn = fn(&ComputedValues) -> Option; + fn from_computed_unanimatable(_: &ComputedValues) -> Option { + None + } + % for prop in data.longhands: + % if prop.animatable and not prop.logical: + #[allow(non_snake_case)] + fn from_computed_${prop.ident}(style: &ComputedValues) -> Option { + let computed = style.clone_${prop.ident}(); + Some(AnimationValue::${prop.camel_case}( + % if prop.animation_type == "discrete": + computed + % else: + computed.to_animated_value(&crate::values::animated::Context { style }) + % endif + )) + } + % endif + % endfor + static FROM_COMPUTED: [FromComputedFn; crate::properties::property_counts::LONGHANDS] = [ % for prop in data.longhands: % if prop.animatable and not prop.logical: - LonghandId::${prop.camel_case} => { - let computed = style.clone_${prop.ident}(); - AnimationValue::${prop.camel_case}( - % if prop.animation_type == "discrete": - computed - % else: - computed.to_animated_value(&crate::values::animated::Context { style }) - % endif - ) - } + from_computed_${prop.ident}, + % else: + from_computed_unanimatable, % endif % endfor - _ => return None, - }) + ]; + FROM_COMPUTED[property as usize](style) } /// Update `style` with the value of this `AnimationValue`. @@ -480,30 +587,46 @@ impl AnimationValue { /// when animated font-size. #[cfg(feature = "servo")] pub fn set_in_style_for_servo(&self, style: &mut ComputedValues, context: &SharedStyleContext) { - match self { + type SetInStyleFn = fn(&AnimationValue, &mut ComputedValues); + fn set_in_style_unanimatable(_: &AnimationValue, _: &mut ComputedValues) { + unreachable!() + } + % for prop in data.longhands: + % if prop.animatable and not prop.logical: + #[allow(non_snake_case)] + fn set_in_style_${prop.ident}(v: &AnimationValue, style: &mut ComputedValues) { + let AnimationValue::${prop.camel_case}(ref value) = *v else { + unsafe { debug_unreachable!() } + }; + let value: longhands::${prop.ident}::computed_value::T = + % if prop.animation_type != "discrete": + ToAnimatedValue::from_animated_value(value.clone()); + % else: + value.clone(); + % endif + style.mutate_${prop.style_struct.name_lower}().set_${prop.ident}(value); + } + % endif + % endfor + static SET_IN_STYLE: [SetInStyleFn; crate::properties::property_counts::LONGHANDS] = [ % for prop in data.longhands: % if prop.animatable and not prop.logical: - AnimationValue::${prop.camel_case}(ref value) => { - let value: longhands::${prop.ident}::computed_value::T = - % if prop.animation_type != "discrete": - ToAnimatedValue::from_animated_value(value.clone()); - % else: - value.clone(); - % endif - style.mutate_${prop.style_struct.name_lower}().set_${prop.ident}(value); - } + set_in_style_${prop.ident}, % else: - AnimationValue::${prop.camel_case}(..) => unreachable!(), + set_in_style_unanimatable, % endif % endfor - AnimationValue::Custom(CustomAnimatedValue { name, value }) => { - let registration = context.stylist.get_custom_property_registration(&name); - match value { - Some(value) => style.custom_properties.insert(registration, name, value.clone()), - None => style.custom_properties.remove(registration, name), - } - }, + ]; + if let AnimationValue::Custom(CustomAnimatedValue { name, value }) = self { + let registration = context.stylist.get_custom_property_registration(&name); + match value { + Some(value) => style.custom_properties.insert(registration, name, value.clone()), + None => style.custom_properties.remove(registration, name), + } + return; } + let tag = unsafe { *(self as *const _ as *const u16) }; + SET_IN_STYLE[tag as usize](self, style) } } @@ -526,37 +649,69 @@ impl Animate for AnimationValue { panic!("Unexpected AnimationValue::animate call"); } - match *self { - <% keyfunc = lambda x: (x.animated_type(), x.animation_type == "discrete") %> - % for (ty, discrete), props in groupby(animated, key=keyfunc): - ${" |\n".join("{}(ref this)".format(prop.camel_case) for prop in props)} => { - let other_repr = - &*(other as *const _ as *const AnimationValueVariantRepr<${ty}>); - % if discrete: - let value = animate_discrete(this, &other_repr.value, procedure)?; - % else: - let value = this.animate(&other_repr.value, procedure)?; - % endif + <% + keyfunc = lambda x: (x.animated_type(), x.animation_type == "discrete") + animate_group = {} + for key, props in groupby(animated, key=keyfunc): + for p in props: + animate_group[p.ident] = key + %> + type AnimateFn = unsafe fn( + &AnimationValue, + &AnimationValue, + Procedure, + ) -> Result; + unsafe fn animate_unanimatable( + _: &AnimationValue, + _: &AnimationValue, + _: Procedure, + ) -> Result { + debug_unreachable!() + } + % for prop in animated: + <% ty, discrete = animate_group[prop.ident] %> + #[allow(non_snake_case)] + unsafe fn animate_${prop.ident}( + this: &AnimationValue, + other: &AnimationValue, + procedure: Procedure, + ) -> Result { + let ${prop.camel_case}(ref this_value) = *this else { + debug_unreachable!() + }; + let other_repr = + &*(other as *const _ as *const AnimationValueVariantRepr<${ty}>); + % if discrete: + let value = animate_discrete(this_value, &other_repr.value, procedure)?; + % else: + let value = this_value.animate(&other_repr.value, procedure)?; + % endif - let mut out = mem::MaybeUninit::uninit(); - ptr::write( - out.as_mut_ptr() as *mut AnimationValueVariantRepr<${ty}>, - AnimationValueVariantRepr { - tag: this_tag, - value, - }, - ); - out.assume_init() - }, + let mut out = mem::MaybeUninit::uninit(); + ptr::write( + out.as_mut_ptr() as *mut AnimationValueVariantRepr<${ty}>, + AnimationValueVariantRepr { + tag: *(this as *const _ as *const u16), + value, + }, + ); + Ok(out.assume_init()) + } + % endfor + static ANIMATE: [AnimateFn; crate::properties::property_counts::LONGHANDS] = [ + % for prop in data.longhands: + % if prop.animatable and not prop.logical: + animate_${prop.ident}, + % else: + animate_unanimatable, + % endif % endfor - ${" |\n".join("{}(void)".format(prop.camel_case) for prop in unanimated)} => { - void::unreachable(void) - }, - Custom(ref self_value) => { - let Custom(ref other_value) = *other else { unreachable!() }; - Custom(self_value.animate(other_value, procedure)?) - }, + ]; + if let Custom(ref self_value) = *self { + let Custom(ref other_value) = *other else { unreachable!() }; + return Ok(Custom(self_value.animate(other_value, procedure)?)); } + ANIMATE[this_tag as usize](self, other, procedure)? }) } } @@ -579,17 +734,51 @@ impl ComputeSquaredDistance for AnimationValue { panic!("Unexpected AnimationValue::compute_squared_distance call"); } - match *self { - % for ty, props in groupby(nondiscrete, key=lambda x: x.animated_type()): - ${" |\n".join("{}(ref this)".format(prop.camel_case) for prop in props)} => { - let other_repr = - &*(other as *const _ as *const AnimationValueVariantRepr<${ty}>); - - this.compute_squared_distance(&other_repr.value) - } + <% + distance_group = {} + for ty, props in groupby(nondiscrete, key=lambda x: x.animated_type()): + for p in props: + distance_group[p.ident] = ty + %> + type DistanceFn = unsafe fn( + &AnimationValue, + &AnimationValue, + ) -> Result; + unsafe fn distance_err( + _: &AnimationValue, + _: &AnimationValue, + ) -> Result { + Err(()) + } + % for prop in nondiscrete: + <% ty = distance_group[prop.ident] %> + #[allow(non_snake_case)] + unsafe fn distance_${prop.ident}( + this: &AnimationValue, + other: &AnimationValue, + ) -> Result { + let ${prop.camel_case}(ref this_value) = *this else { + debug_unreachable!() + }; + let other_repr = + &*(other as *const _ as *const AnimationValueVariantRepr<${ty}>); + this_value.compute_squared_distance(&other_repr.value) + } + % endfor + <% nondiscrete_idents = set(p.ident for p in nondiscrete) %> + static DISTANCE: [DistanceFn; crate::properties::property_counts::LONGHANDS] = [ + % for prop in data.longhands: + % if prop.ident in nondiscrete_idents: + distance_${prop.ident}, + % else: + distance_err, + % endif % endfor - _ => Err(()), + ]; + if (this_tag as usize) >= crate::properties::property_counts::LONGHANDS { + return Err(()); } + DISTANCE[this_tag as usize](self, other) } } } diff --git a/style/properties/properties.mako.rs b/style/properties/properties.mako.rs index 5864c5caf4..c1e4a45463 100644 --- a/style/properties/properties.mako.rs +++ b/style/properties/properties.mako.rs @@ -1702,29 +1702,51 @@ impl ComputedValues { context: Option<&mut resolved::Context>, dest: &mut CssStringWriter, ) -> fmt::Result { - let mut dest = CssWriter::new(dest); - let property_id = property_id.to_physical(self.writing_mode); - match property_id { - % for specified_type, props in groupby(data.longhands, key=lambda x: x.specified_type()): - <% props = list(props) %> - ${" |\n".join("LonghandId::{}".format(p.camel_case) for p in props)} => { - let value = match property_id { - % for prop in props: - % if not prop.logical: - LonghandId::${prop.camel_case} => self.clone_${prop.ident}(), - % endif - % endfor - _ => unsafe { debug_unreachable!() }, - }; - if let Some(c) = context { - c.current_longhand = Some(property_id); - value.to_resolved_value(c).to_css(&mut dest) - } else { - value.to_css(&mut dest) - } + type ToCssFn = fn( + &ComputedValues, + LonghandId, + Option<&mut resolved::Context>, + &mut CssWriter, + ) -> fmt::Result; + fn logical_unreachable( + _: &ComputedValues, + _: LonghandId, + _: Option<&mut resolved::Context>, + _: &mut CssWriter, + ) -> fmt::Result { + unsafe { debug_unreachable!() } + } + % for prop in data.longhands: + % if not prop.logical: + #[allow(non_snake_case)] + fn to_css_${prop.ident}( + style: &ComputedValues, + property_id: LonghandId, + context: Option<&mut resolved::Context>, + dest: &mut CssWriter, + ) -> fmt::Result { + let value = style.clone_${prop.ident}(); + if let Some(c) = context { + c.current_longhand = Some(property_id); + value.to_resolved_value(c).to_css(dest) + } else { + value.to_css(dest) } - % endfor } + % endif + % endfor + static TO_CSS: [ToCssFn; property_counts::LONGHANDS] = [ + % for prop in data.longhands: + % if prop.logical: + logical_unreachable, + % else: + to_css_${prop.ident}, + % endif + % endfor + ]; + let mut dest = CssWriter::new(dest); + let property_id = property_id.to_physical(self.writing_mode); + TO_CSS[property_id as usize](self, property_id, context, &mut dest) } /// Returns the computed value of the given longhand as a @@ -1733,23 +1755,29 @@ impl ComputedValues { &self, property_id: LonghandId, ) -> Option { - let property_id = property_id.to_physical(self.writing_mode); - match property_id { - % for specified_type, props in groupby(data.longhands, key=lambda x: x.specified_type()): - <% props = list(props) %> - ${" |\n".join("LonghandId::{}".format(p.camel_case) for p in props)} => { - let value = match property_id { - % for prop in props: - % if not prop.logical: - LonghandId::${prop.camel_case} => self.clone_${prop.ident}(), - % endif - % endfor - _ => unsafe { debug_unreachable!() }, - }; - value.to_typed_value_list() - } - % endfor + type ToTypedFn = fn(&ComputedValues) -> Option; + fn logical_unreachable(_: &ComputedValues) -> Option { + unsafe { debug_unreachable!() } + } + % for prop in data.longhands: + % if not prop.logical: + #[allow(non_snake_case)] + fn to_typed_${prop.ident}(style: &ComputedValues) -> Option { + style.clone_${prop.ident}().to_typed_value_list() } + % endif + % endfor + static TO_TYPED: [ToTypedFn; property_counts::LONGHANDS] = [ + % for prop in data.longhands: + % if prop.logical: + logical_unreachable, + % else: + to_typed_${prop.ident}, + % endif + % endfor + ]; + let property_id = property_id.to_physical(self.writing_mode); + TO_TYPED[property_id as usize](self) } /// Returns the given longhand's resolved value as a property declaration. @@ -1758,46 +1786,76 @@ impl ComputedValues { property_id: LonghandId, context: Option<&mut resolved::Context>, ) -> PropertyDeclaration { - let physical_property_id = property_id.to_physical(self.writing_mode); - match physical_property_id { - % for specified_type, props in groupby(data.longhands, key=lambda x: x.specified_type()): - <% props = list(props) %> - ${" |\n".join("LonghandId::{}".format(p.camel_case) for p in props)} => { - let mut computed_value = match physical_property_id { - % for prop in props: - % if not prop.logical: - LonghandId::${prop.camel_case} => self.clone_${prop.ident}(), - % endif - % endfor - _ => unsafe { debug_unreachable!() }, - }; - if let Some(c) = context { - c.current_longhand = Some(physical_property_id); - let resolved = computed_value.to_resolved_value(c); - computed_value = ToResolvedValue::from_resolved_value(resolved); - } - let specified = ToComputedValue::from_computed_value(&computed_value); - % if props[0].boxed: - let specified = Box::new(specified); - % endif - % if len(props) == 1: - PropertyDeclaration::${props[0].camel_case}(specified) - % else: - unsafe { - let mut out = mem::MaybeUninit::uninit(); - ptr::write( - out.as_mut_ptr() as *mut PropertyDeclarationVariantRepr<${specified_type}>, - PropertyDeclarationVariantRepr { - tag: property_id as u16, - value: specified, - }, - ); - out.assume_init() - } - % endif + <% + group_info = {} + for specified_type, props in groupby(data.longhands, key=lambda x: x.specified_type()): + props = list(props) + for p in props: + group_info[p.ident] = (specified_type, props) + %> + type ToDeclFn = fn( + &ComputedValues, + LonghandId, + LonghandId, + Option<&mut resolved::Context>, + ) -> PropertyDeclaration; + fn logical_unreachable( + _: &ComputedValues, + _: LonghandId, + _: LonghandId, + _: Option<&mut resolved::Context>, + ) -> PropertyDeclaration { + unsafe { debug_unreachable!() } + } + % for prop in data.longhands: + % if not prop.logical: + <% specified_type, props = group_info[prop.ident] %> + #[allow(non_snake_case, unused_variables)] + fn to_decl_${prop.ident}( + style: &ComputedValues, + property_id: LonghandId, + physical_property_id: LonghandId, + context: Option<&mut resolved::Context>, + ) -> PropertyDeclaration { + let mut computed_value = style.clone_${prop.ident}(); + if let Some(c) = context { + c.current_longhand = Some(physical_property_id); + let resolved = computed_value.to_resolved_value(c); + computed_value = ToResolvedValue::from_resolved_value(resolved); } - % endfor + let specified = ToComputedValue::from_computed_value(&computed_value); + % if prop.boxed: + let specified = Box::new(specified); + % endif + % if len(props) == 1: + PropertyDeclaration::${prop.camel_case}(specified) + % else: + unsafe { + let mut out = mem::MaybeUninit::uninit(); + ptr::write( + out.as_mut_ptr() as *mut PropertyDeclarationVariantRepr<${specified_type}>, + PropertyDeclarationVariantRepr { + tag: property_id as u16, + value: specified, + }, + ); + out.assume_init() + } + % endif } + % endif + % endfor + static TO_DECL: [ToDeclFn; property_counts::LONGHANDS] = [ + % for prop in data.longhands: + % if prop.logical: + logical_unreachable, + % else: + to_decl_${prop.ident}, + % endif + % endfor + ]; + let physical_property_id = property_id.to_physical(self.writing_mode); + TO_DECL[physical_property_id as usize](self, property_id, physical_property_id, context) } /// Resolves the currentColor keyword.