diff --git a/components/style/gecko/generated/bindings.rs b/components/style/gecko/generated/bindings.rs index 7774ccbeb0a..79222be48d2 100644 --- a/components/style/gecko/generated/bindings.rs +++ b/components/style/gecko/generated/bindings.rs @@ -1133,6 +1133,14 @@ extern "C" { pub fn Gecko_nsStyleSVG_CopyDashArray(dst: *mut nsStyleSVG, src: *const nsStyleSVG); } +extern "C" { + pub fn Gecko_nsStyleSVG_SetContextPropertiesLength(svg: *mut nsStyleSVG, + len: u32); +} +extern "C" { + pub fn Gecko_nsStyleSVG_CopyContextProperties(dst: *mut nsStyleSVG, + src: *const nsStyleSVG); +} extern "C" { pub fn Gecko_NewURLValue(uri: ServoBundledURI) -> *mut URLValue; } @@ -1307,6 +1315,11 @@ extern "C" { pres_context: RawGeckoPresContextBorrowed); } +extern "C" { + pub fn Gecko_nsStyleFont_FixupMinFontSize(font: *mut nsStyleFont, + pres_context: + RawGeckoPresContextBorrowed); +} extern "C" { pub fn Gecko_GetBaseSize(lang: *mut nsIAtom) -> FontSizePrefs; } diff --git a/components/style/gecko/generated/structs_debug.rs b/components/style/gecko/generated/structs_debug.rs index 923dda94562..9232136c300 100644 --- a/components/style/gecko/generated/structs_debug.rs +++ b/components/style/gecko/generated/structs_debug.rs @@ -806,6 +806,11 @@ pub mod root { 4; pub const NS_STYLE_CONTEXT_PROPERTY_FILL: ::std::os::raw::c_uint = 1; pub const NS_STYLE_CONTEXT_PROPERTY_STROKE: ::std::os::raw::c_uint = 2; + pub const NS_STYLE_WINDOW_SHADOW_NONE: ::std::os::raw::c_uint = 0; + pub const NS_STYLE_WINDOW_SHADOW_DEFAULT: ::std::os::raw::c_uint = 1; + pub const NS_STYLE_WINDOW_SHADOW_MENU: ::std::os::raw::c_uint = 2; + pub const NS_STYLE_WINDOW_SHADOW_TOOLTIP: ::std::os::raw::c_uint = 3; + pub const NS_STYLE_WINDOW_SHADOW_SHEET: ::std::os::raw::c_uint = 4; pub const NS_STYLE_DOMINANT_BASELINE_AUTO: ::std::os::raw::c_uint = 0; pub const NS_STYLE_DOMINANT_BASELINE_USE_SCRIPT: ::std::os::raw::c_uint = 1; @@ -2191,7 +2196,8 @@ pub mod root { #[repr(C)] #[derive(Debug, Copy)] pub struct FontVariation { - pub _bindgen_opaque_blob: [u32; 2usize], + pub mTag: u32, + pub mValue: f32, } #[test] fn bindgen_test_layout_FontVariation() { @@ -2202,6 +2208,17 @@ pub mod root { concat ! ( "Alignment of " , stringify ! ( FontVariation ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const FontVariation ) ) . mTag as * + const _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( + FontVariation ) , "::" , stringify ! ( mTag ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const FontVariation ) ) . mValue as + * const _ as usize } , 4usize , concat ! ( + "Alignment of field: " , stringify ! ( + FontVariation ) , "::" , stringify ! ( mValue ) + )); } impl Clone for FontVariation { fn clone(&self) -> Self { *self } diff --git a/components/style/gecko/generated/structs_release.rs b/components/style/gecko/generated/structs_release.rs index ac4c81cb1ca..880ab88cbfe 100644 --- a/components/style/gecko/generated/structs_release.rs +++ b/components/style/gecko/generated/structs_release.rs @@ -806,6 +806,11 @@ pub mod root { 4; pub const NS_STYLE_CONTEXT_PROPERTY_FILL: ::std::os::raw::c_uint = 1; pub const NS_STYLE_CONTEXT_PROPERTY_STROKE: ::std::os::raw::c_uint = 2; + pub const NS_STYLE_WINDOW_SHADOW_NONE: ::std::os::raw::c_uint = 0; + pub const NS_STYLE_WINDOW_SHADOW_DEFAULT: ::std::os::raw::c_uint = 1; + pub const NS_STYLE_WINDOW_SHADOW_MENU: ::std::os::raw::c_uint = 2; + pub const NS_STYLE_WINDOW_SHADOW_TOOLTIP: ::std::os::raw::c_uint = 3; + pub const NS_STYLE_WINDOW_SHADOW_SHEET: ::std::os::raw::c_uint = 4; pub const NS_STYLE_DOMINANT_BASELINE_AUTO: ::std::os::raw::c_uint = 0; pub const NS_STYLE_DOMINANT_BASELINE_USE_SCRIPT: ::std::os::raw::c_uint = 1; @@ -2097,7 +2102,8 @@ pub mod root { #[repr(C)] #[derive(Debug, Copy)] pub struct FontVariation { - pub _bindgen_opaque_blob: [u32; 2usize], + pub mTag: u32, + pub mValue: f32, } #[test] fn bindgen_test_layout_FontVariation() { @@ -2108,6 +2114,17 @@ pub mod root { concat ! ( "Alignment of " , stringify ! ( FontVariation ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const FontVariation ) ) . mTag as * + const _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( + FontVariation ) , "::" , stringify ! ( mTag ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const FontVariation ) ) . mValue as + * const _ as usize } , 4usize , concat ! ( + "Alignment of field: " , stringify ! ( + FontVariation ) , "::" , stringify ! ( mValue ) + )); } impl Clone for FontVariation { fn clone(&self) -> Self { *self } diff --git a/components/style/gecko/rules.rs b/components/style/gecko/rules.rs index 80aa7a7acb2..e9165f7629f 100644 --- a/components/style/gecko/rules.rs +++ b/components/style/gecko/rules.rs @@ -17,6 +17,7 @@ use gecko_bindings::sugar::ns_css_value::ToNsCssValue; use gecko_bindings::sugar::refptr::{RefPtr, UniqueRefPtr}; use shared_lock::{ToCssWithGuard, SharedRwLockReadGuard}; use std::{fmt, str}; +use values::generics::FontSettings; /// A @font-face rule pub type FontFaceRule = RefPtr; @@ -36,8 +37,8 @@ impl ToNsCssValue for font_weight::T { impl ToNsCssValue for font_feature_settings::T { fn convert(self, nscssvalue: &mut nsCSSValue) { match self { - font_feature_settings::T::Normal => nscssvalue.set_normal(), - font_feature_settings::T::Tag(tags) => { + FontSettings::Normal => nscssvalue.set_normal(), + FontSettings::Tag(tags) => { nscssvalue.set_pair_list(tags.into_iter().map(|entry| { let mut feature = nsCSSValue::null(); let mut raw = [0u8; 4]; @@ -45,7 +46,7 @@ impl ToNsCssValue for font_feature_settings::T { feature.set_string(str::from_utf8(&raw).unwrap()); let mut index = nsCSSValue::null(); - index.set_integer(entry.value as i32); + index.set_integer(entry.value.0 as i32); (feature, index) })) diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 03899d928ce..aeacf2bbefc 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1486,27 +1486,28 @@ fn static_assert() { font-synthesis -x-lang font-variant-alternates font-variant-east-asian font-variant-ligatures font-variant-numeric font-language-override - font-feature-settings""" + font-feature-settings font-variation-settings + -moz-min-font-size-ratio""" %> <%self:impl_trait style_struct_name="Font" skip_longhands="${skip_font_longhands}" skip_additionals="*"> pub fn set_font_feature_settings(&mut self, v: longhands::font_feature_settings::computed_value::T) { - use properties::longhands::font_feature_settings::computed_value::T; + use values::generics::FontSettings; let current_settings = &mut self.gecko.mFont.fontFeatureSettings; current_settings.clear_pod(); match v { - T::Normal => unsafe { current_settings.set_len_pod(0) }, + FontSettings::Normal => (), // do nothing, length is already 0 - T::Tag(feature_settings) => { + FontSettings::Tag(feature_settings) => { unsafe { current_settings.set_len_pod(feature_settings.len() as u32) }; for (current, feature) in current_settings.iter_mut().zip(feature_settings) { current.mTag = feature.tag; - current.mValue = feature.value; + current.mValue = feature.value.0; } } }; @@ -1526,6 +1527,40 @@ fn static_assert() { } } + pub fn set_font_variation_settings(&mut self, v: longhands::font_variation_settings::computed_value::T) { + use values::generics::FontSettings; + + let current_settings = &mut self.gecko.mFont.fontVariationSettings; + current_settings.clear_pod(); + + match v { + FontSettings::Normal => (), // do nothing, length is already 0 + + FontSettings::Tag(feature_settings) => { + unsafe { current_settings.set_len_pod(feature_settings.len() as u32) }; + + for (current, feature) in current_settings.iter_mut().zip(feature_settings) { + current.mTag = feature.tag; + current.mValue = feature.value.0; + } + } + }; + } + + pub fn copy_font_variation_settings_from(&mut self, other: &Self ) { + let current_settings = &mut self.gecko.mFont.fontVariationSettings; + let feature_settings = &other.gecko.mFont.fontVariationSettings; + let settings_length = feature_settings.len() as u32; + + current_settings.clear_pod(); + unsafe { current_settings.set_len_pod(settings_length) }; + + for (current, feature) in current_settings.iter_mut().zip(feature_settings.iter()) { + current.mTag = feature.mTag; + current.mValue = feature.mValue; + } + } + pub fn fixup_none_generic(&mut self, device: &Device) { unsafe { bindings::Gecko_nsStyleFont_FixupNoneGeneric(&mut self.gecko, &*device.pres_context) @@ -1595,7 +1630,6 @@ fn static_assert() { // actual computed size, and the other of which (mFont.size) is the 'display // size' which takes font zooming into account. We don't handle font zooming yet. pub fn set_font_size(&mut self, v: longhands::font_size::computed_value::T) { - self.gecko.mFont.size = v.0; self.gecko.mSize = v.0; self.gecko.mScriptUnconstrainedSize = v.0; } @@ -1603,21 +1637,27 @@ fn static_assert() { /// Set font size, taking into account scriptminsize and scriptlevel /// Returns Some(size) if we have to recompute the script unconstrained size pub fn apply_font_size(&mut self, v: longhands::font_size::computed_value::T, - parent: &Self) -> Option { + parent: &Self, + device: &Device) -> Option { let (adjusted_size, adjusted_unconstrained_size) = self.calculate_script_level_size(parent); // In this case, we have been unaffected by scriptminsize, ignore it if parent.gecko.mSize == parent.gecko.mScriptUnconstrainedSize && adjusted_size == adjusted_unconstrained_size { self.set_font_size(v); + self.fixup_font_min_size(device); None } else { - self.gecko.mFont.size = v.0; self.gecko.mSize = v.0; + self.fixup_font_min_size(device); Some(Au(parent.gecko.mScriptUnconstrainedSize)) } } + pub fn fixup_font_min_size(&mut self, device: &Device) { + unsafe { bindings::Gecko_nsStyleFont_FixupMinFontSize(&mut self.gecko, &*device.pres_context) } + } + pub fn apply_unconstrained_font_size(&mut self, v: Au) { self.gecko.mScriptUnconstrainedSize = v.0; } @@ -1726,7 +1766,8 @@ fn static_assert() { /// /// Returns true if the inherited keyword size was actually used pub fn inherit_font_size_from(&mut self, parent: &Self, - kw_inherited_size: Option) -> bool { + kw_inherited_size: Option, + device: &Device) -> bool { let (adjusted_size, adjusted_unconstrained_size) = self.calculate_script_level_size(parent); if adjusted_size.0 != parent.gecko.mSize || @@ -1745,23 +1786,23 @@ fn static_assert() { // In the case that MathML has given us an adjusted size, apply it. // Keep track of the unconstrained adjusted size. - self.gecko.mFont.size = adjusted_size.0; self.gecko.mSize = adjusted_size.0; self.gecko.mScriptUnconstrainedSize = adjusted_unconstrained_size.0; + self.fixup_font_min_size(device); false } else if let Some(size) = kw_inherited_size { // Parent element was a keyword-derived size. - self.gecko.mFont.size = size.0; self.gecko.mSize = size.0; // MathML constraints didn't apply here, so we can ignore this. self.gecko.mScriptUnconstrainedSize = size.0; + self.fixup_font_min_size(device); true } else { // MathML isn't affecting us, and our parent element does not // have a keyword-derived size. Set things normally. - self.gecko.mFont.size = parent.gecko.mFont.size; self.gecko.mSize = parent.gecko.mSize; self.gecko.mScriptUnconstrainedSize = parent.gecko.mScriptUnconstrainedSize; + self.fixup_font_min_size(device); false } } @@ -1864,6 +1905,21 @@ fn static_assert() { } ${impl_simple_copy('font_variant_numeric', 'mFont.variantNumeric')} + + #[allow(non_snake_case)] + pub fn set__moz_min_font_size_ratio(&mut self, v: longhands::_moz_min_font_size_ratio::computed_value::T) { + let percentage = if v.0 > 255. { + 255. + } else if v.0 < 0. { + 0. + } else { + v.0 + }; + + self.gecko.mMinFontSizeRatio = percentage as u8; + } + + ${impl_simple_copy('_moz_min_font_size_ratio', 'mMinFontSizeRatio')} <%def name="impl_copy_animation_or_transition_value(type, ident, gecko_ffi_name)"> @@ -4003,7 +4059,7 @@ clip-path <%self:impl_trait style_struct_name="InheritedSVG" - skip_longhands="paint-order stroke-dasharray stroke-dashoffset stroke-width" + skip_longhands="paint-order stroke-dasharray stroke-dashoffset stroke-width -moz-context-properties" skip_additionals="*"> pub fn set_paint_order(&mut self, v: longhands::paint_order::computed_value::T) { use self::longhands::paint_order; @@ -4111,6 +4167,34 @@ clip-path _ => unreachable!(), } } + + #[allow(non_snake_case)] + pub fn set__moz_context_properties(&mut self, v: I) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator + { + let v = v.into_iter(); + unsafe { + bindings::Gecko_nsStyleSVG_SetContextPropertiesLength(&mut self.gecko, v.len() as u32); + } + + self.gecko.mContextPropsBits = 0; + for (mut gecko, servo) in self.gecko.mContextProps.iter_mut().zip(v) { + if servo.0 == atom!("fill") { + self.gecko.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_FILL as u8; + } else if servo.0 == atom!("stroke") { + self.gecko.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_STROKE as u8; + } + unsafe { gecko.set_raw_from_addrefed::(servo.0.into_addrefed()) } + } + } + + #[allow(non_snake_case)] + pub fn copy__moz_context_properties_from(&mut self, other: &Self) { + unsafe { + bindings::Gecko_nsStyleSVG_CopyContextProperties(&mut self.gecko, &other.gecko); + } + } <%self:impl_trait style_struct_name="Color" diff --git a/components/style/properties/longhand/column.mako.rs b/components/style/properties/longhand/column.mako.rs index 91b42fa5350..88a17a4c0f6 100644 --- a/components/style/properties/longhand/column.mako.rs +++ b/components/style/properties/longhand/column.mako.rs @@ -54,9 +54,8 @@ ${helpers.predefined_type("column-rule-color", "CSSColor", complex_color=True, need_clone=True, spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-color")} -// It's not implemented in servo or gecko yet. ${helpers.single_keyword("column-span", "none all", - products="none", animation_value_type="none", + products="gecko", animation_value_type="none", spec="https://drafts.csswg.org/css-multicol/#propdef-column-span")} ${helpers.single_keyword("column-rule-style", diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 110ae7d6800..88292db54c8 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -925,10 +925,12 @@ ${helpers.single_keyword_system("font-variant-caps", } % endif - let parent_unconstrained = context.mutate_style() - .mutate_font() - .apply_font_size(computed, - parent); + let parent_unconstrained = { + let (style, device) = context.mutate_style_with_device(); + + style.mutate_font().apply_font_size(computed, parent, device) + }; + if let Some(parent) = parent_unconstrained { let new_unconstrained = specified_value @@ -946,13 +948,14 @@ ${helpers.single_keyword_system("font-variant-caps", let kw_inherited_size = context.style().font_size_keyword.map(|(kw, ratio)| { SpecifiedValue::Keyword(kw, ratio).to_computed_value(context) }); - let used_kw = context.mutate_style().mutate_font() - .inherit_font_size_from(parent, kw_inherited_size); + let parent_kw = context.inherited_style.font_computation_data.font_size_keyword; + let (style, device) = context.mutate_style_with_device(); + let used_kw = style.mutate_font() + .inherit_font_size_from(parent, kw_inherited_size, device); if used_kw { - context.mutate_style().font_size_keyword = - context.inherited_style.font_computation_data.font_size_keyword; + style.font_size_keyword = parent_kw; } else { - context.mutate_style().font_size_keyword = None; + style.font_size_keyword = None; } } @@ -961,9 +964,12 @@ ${helpers.single_keyword_system("font-variant-caps", // compute to the same value and depends on the font let computed = longhands::font_size::get_initial_specified_value() .to_computed_value(context); - context.mutate_style().mutate_${data.current_style_struct.name_lower}() - .set_font_size(computed); - context.mutate_style().font_size_keyword = Some((Default::default(), 1.)); + let (style, _device) = context.mutate_style_with_device(); + style.mutate_font().set_font_size(computed); + % if product == "gecko": + style.mutate_font().fixup_font_min_size(_device); + % endif + style.font_size_keyword = Some((Default::default(), 1.)); } @@ -1774,6 +1780,7 @@ ${helpers.single_keyword_system("font-variant-position", use properties::longhands::system_font::SystemFont; use std::fmt; use style_traits::ToCss; + use values::generics::FontSettings; #[derive(Debug, Clone, PartialEq)] pub enum SpecifiedValue { @@ -1785,120 +1792,18 @@ ${helpers.single_keyword_system("font-variant-position", <%self:simple_system_boilerplate name="font_feature_settings"> pub mod computed_value { - use cssparser::Parser; - use parser::{Parse, ParserContext}; - use std::fmt; - use style_traits::ToCss; - - #[derive(Clone, Debug, Eq, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum T { - Normal, - Tag(Vec) - } - - #[derive(Clone, Debug, Eq, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct FeatureTagValue { - pub tag: u32, - pub value: u32 - } - - impl ToCss for T { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - T::Normal => dest.write_str("normal"), - T::Tag(ref ftvs) => { - let mut iter = ftvs.iter(); - // handle head element - try!(iter.next().unwrap().to_css(dest)); - // handle tail, precede each with a delimiter - for ftv in iter { - try!(dest.write_str(", ")); - try!(ftv.to_css(dest)); - } - Ok(()) - } - } - } - } - - impl Parse for T { - /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings - fn parse(context: &ParserContext, input: &mut Parser) -> Result { - if input.try(|i| i.expect_ident_matching("normal")).is_ok() { - return Ok(T::Normal); - } - input.parse_comma_separated(|i| FeatureTagValue::parse(context, i)).map(T::Tag) - } - } - - impl ToCss for FeatureTagValue { - fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - use std::str; - use byteorder::{WriteBytesExt, BigEndian}; - use cssparser::serialize_string; - - let mut raw: Vec = vec!(); - raw.write_u32::(self.tag).unwrap(); - serialize_string(str::from_utf8(&raw).unwrap_or_default(), dest)?; - - match self.value { - 1 => Ok(()), - 0 => dest.write_str(" off"), - x => write!(dest, " {}", x) - } - } - } - - impl Parse for FeatureTagValue { - /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings - /// [ on | off | ] - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - use std::io::Cursor; - use byteorder::{ReadBytesExt, BigEndian}; - - let tag = try!(input.expect_string()); - - // allowed strings of length 4 containing chars: - if tag.len() != 4 || - tag.chars().any(|c| c < ' ' || c > '~') - { - return Err(()) - } - - let mut raw = Cursor::new(tag.as_bytes()); - let u_tag = raw.read_u32::().unwrap(); - - if let Ok(value) = input.try(|input| input.expect_integer()) { - // handle integer, throw if it is negative - if value >= 0 { - Ok(FeatureTagValue { tag: u_tag, value: value as u32 }) - } else { - Err(()) - } - } else if let Ok(_) = input.try(|input| input.expect_ident_matching("on")) { - // on is an alias for '1' - Ok(FeatureTagValue { tag: u_tag, value: 1 }) - } else if let Ok(_) = input.try(|input| input.expect_ident_matching("off")) { - // off is an alias for '0' - Ok(FeatureTagValue { tag: u_tag, value: 0 }) - } else { - // empty value is an alias for '1' - Ok(FeatureTagValue { tag: u_tag, value: 1 }) - } - } - } + use values::generics::{FontSettings, FontSettingTagInt}; + pub type T = FontSettings; } #[inline] pub fn get_initial_value() -> computed_value::T { - computed_value::T::Normal + FontSettings::Normal } #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue::Value(computed_value::T::Normal) + SpecifiedValue::Value(FontSettings::Normal) } /// normal | # @@ -1907,6 +1812,40 @@ ${helpers.single_keyword_system("font-variant-position", } +<% +# This spec link is too long to fit elsewhere +variation_spec = """\ +https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control-the-font-variation-settings-property\ +""" +%> +<%helpers:longhand name="font-variation-settings" products="gecko" animation_value_type="none" + spec="${variation_spec}"> + use values::computed::ComputedValueAsSpecified; + use values::generics::FontSettings; + + impl ComputedValueAsSpecified for SpecifiedValue {} + + pub type SpecifiedValue = computed_value::T; + + no_viewport_percentage!(SpecifiedValue); + + + pub mod computed_value { + use values::generics::{FontSettings, FontSettingTagFloat}; + pub type T = FontSettings; + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + FontSettings::Normal + } + + /// normal | # + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + computed_value::T::parse(context, input) + } + + <%helpers:longhand name="font-language-override" products="gecko" animation_value_type="none" extra_prefixes="moz" boxed="True" spec="https://drafts.csswg.org/css-fonts-3/#propdef-font-language-override"> @@ -2453,3 +2392,11 @@ ${helpers.single_keyword("-moz-osx-font-smoothing", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/font-smooth)", animation_value_type="none", need_clone=True)} + +${helpers.predefined_type("-moz-min-font-size-ratio", + "Percentage", + "computed::Percentage::hundred()", + animation_value_type="none", + products="gecko", + internal=True, + spec="Nonstandard (Internal-only)")} diff --git a/components/style/properties/longhand/inherited_svg.mako.rs b/components/style/properties/longhand/inherited_svg.mako.rs index bbc006a4e58..f02cccafaa4 100644 --- a/components/style/properties/longhand/inherited_svg.mako.rs +++ b/components/style/properties/longhand/inherited_svg.mako.rs @@ -268,3 +268,28 @@ ${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)", impl ComputedValueAsSpecified for SpecifiedValue { } +<%helpers:vector_longhand name="-moz-context-properties" + animation_value_type="none" + products="gecko" + spec="Nonstandard (Internal-only)" + internal="True" + allow_empty="True"> + use values::CustomIdent; + use values::computed::ComputedValueAsSpecified; + + no_viewport_percentage!(SpecifiedValue); + + impl ComputedValueAsSpecified for SpecifiedValue { } + + pub type SpecifiedValue = CustomIdent; + + pub mod computed_value { + pub type T = super::SpecifiedValue; + } + + + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + let i = input.expect_ident()?; + CustomIdent::from_ident(i, &["all", "none", "auto"]) + } + diff --git a/components/style/properties/longhand/ui.mako.rs b/components/style/properties/longhand/ui.mako.rs index 25cba0609c5..26186e3e3b6 100644 --- a/components/style/properties/longhand/ui.mako.rs +++ b/components/style/properties/longhand/ui.mako.rs @@ -31,6 +31,13 @@ ${helpers.single_keyword("-moz-window-dragging", "default drag no-drag", product animation_value_type="none", spec="None (Nonstandard Firefox-only property)")} +${helpers.single_keyword("-moz-window-shadow", "none default menu tooltip sheet", products="gecko", + gecko_ffi_name="mWindowShadow", + gecko_constant_prefix="NS_STYLE_WINDOW_SHADOW", + animation_value_type="none", + internal=True, + spec="None (Nonstandard internal property)")} + <%helpers:longhand name="-moz-force-broken-image-icon" products="gecko" animation_value_type="none" diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index f444df89e74..cb845f529f5 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -607,6 +607,7 @@ impl LonghandId { LonghandId::TransitionProperty | LonghandId::XLang | LonghandId::MozScriptLevel | + LonghandId::MozMinFontSizeRatio | % endif LonghandId::FontSize | LonghandId::FontFamily | @@ -1524,6 +1525,7 @@ pub mod style_structs { use super::longhands; use std::hash::{Hash, Hasher}; use logical_geometry::WritingMode; + use media_queries::Device; % for style_struct in data.active_style_structs(): % if style_struct.name == "Font": @@ -1634,14 +1636,15 @@ pub mod style_structs { /// (Servo does not handle MathML, so this just calls copy_font_size_from) pub fn inherit_font_size_from(&mut self, parent: &Self, - _: Option) -> bool { + _: Option, _: &Device) -> bool { self.copy_font_size_from(parent); false } /// (Servo does not handle MathML, so this just calls set_font_size) pub fn apply_font_size(&mut self, v: longhands::font_size::computed_value::T, - _: &Self) -> Option { + _: &Self, + _: &Device) -> Option { self.set_font_size(v); None } @@ -2628,17 +2631,6 @@ pub fn apply_declarations<'a, F, I>(device: &Device, continue } - // 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". - // - // We iterate applicable_declarations twice, first cascading - // "early" properties then "other". - // - // Unfortunately, it’s not easy to check that this - // classification is correct. if % if category_to_cascade_now == "early": ! @@ -2718,6 +2710,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device, // scriptlevel changes. } else if seen.contains(LonghandId::XLang) || seen.contains(LonghandId::MozScriptLevel) || + seen.contains(LonghandId::MozMinFontSizeRatio) || font_family.is_some() { let discriminant = LonghandId::FontSize as usize; let size = PropertyDeclaration::CSSWideKeyword( diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 64cd2f59353..6085e00c39b 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -106,6 +106,8 @@ impl<'a> Context<'a> { pub fn style(&self) -> &StyleBuilder { &self.style } /// A mutable reference to the current style. pub fn mutate_style(&mut self) -> &mut StyleBuilder<'a> { &mut self.style } + /// Get a mutable reference to the current style as well as the device + pub fn mutate_style_with_device(&mut self) -> (&mut StyleBuilder<'a>, &Device) { (&mut self.style, &self.device) } } /// An iterator over a slice of computed values diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index f96773f3d27..cc796f1120c 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -10,7 +10,7 @@ use cssparser::Parser; use euclid::size::Size2D; use parser::{Parse, ParserContext}; use std::fmt; -use style_traits::{HasViewportPercentage, ToCss}; +use style_traits::{HasViewportPercentage, OneOrMoreCommaSeparated, ToCss}; use super::CustomIdent; pub use self::basic_shape::serialize_radius_values; @@ -163,3 +163,152 @@ impl ToCss for CounterStyleOrNone { } } } + +/// A settings tag, defined by a four-character tag and a setting value +/// +/// For font-feature-settings, this is a tag and an integer, +/// for font-variation-settings this is a tag and a float +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct FontSettingTag { + /// A four-character tag, packed into a u32 (one byte per character) + pub tag: u32, + /// The value + pub value: T, +} + +impl OneOrMoreCommaSeparated for FontSettingTag {} + +impl ToCss for FontSettingTag { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + use byteorder::{WriteBytesExt, BigEndian}; + use cssparser::serialize_string; + use std::str; + + let mut raw: Vec = vec!(); + raw.write_u32::(self.tag).unwrap(); + serialize_string(str::from_utf8(&raw).unwrap_or_default(), dest)?; + + self.value.to_css(dest) + } +} + +impl Parse for FontSettingTag { + /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings + /// https://drafts.csswg.org/css-fonts-4/#low-level-font-variation- + /// settings-control-the-font-variation-settings-property + /// [ on | off | ] + /// + fn parse(context: &ParserContext, input: &mut Parser) -> Result { + use byteorder::{ReadBytesExt, BigEndian}; + use std::io::Cursor; + + let tag = try!(input.expect_string()); + + // allowed strings of length 4 containing chars: + if tag.len() != 4 || + tag.chars().any(|c| c < ' ' || c > '~') + { + return Err(()) + } + + let mut raw = Cursor::new(tag.as_bytes()); + let u_tag = raw.read_u32::().unwrap(); + + Ok(FontSettingTag { tag: u_tag, value: T::parse(context, input)? }) + } +} + + +/// A font settings value for font-variation-settings or font-feature-settings +#[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum FontSettings { + /// No settings (default) + Normal, + /// Set of settings + Tag(Vec>) +} + +impl ToCss for FontSettings { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + FontSettings::Normal => dest.write_str("normal"), + FontSettings::Tag(ref ftvs) => ftvs.to_css(dest) + } + } +} + +impl Parse for FontSettings { + /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings + fn parse(context: &ParserContext, input: &mut Parser) -> Result { + if input.try(|i| i.expect_ident_matching("normal")).is_ok() { + return Ok(FontSettings::Normal); + } + Vec::parse(context, input).map(FontSettings::Tag) + } +} + +/// An integer that can also parse "on" and "off", +/// for font-feature-settings +/// +/// Do not use this type anywhere except within FontSettings +/// because it serializes with the preceding space +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct FontSettingTagInt(pub u32); +/// A number value to be used for font-variation-settings +/// +/// Do not use this type anywhere except within FontSettings +/// because it serializes with the preceding space +#[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct FontSettingTagFloat(pub f32); + +impl ToCss for FontSettingTagInt { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match self.0 { + 1 => Ok(()), + 0 => dest.write_str(" off"), + x => write!(dest, " {}", x) + } + } +} + +impl Parse for FontSettingTagInt { + fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + if let Ok(value) = input.try(|input| input.expect_integer()) { + // handle integer, throw if it is negative + if value >= 0 { + Ok(FontSettingTagInt(value as u32)) + } else { + Err(()) + } + } else if let Ok(_) = input.try(|input| input.expect_ident_matching("on")) { + // on is an alias for '1' + Ok(FontSettingTagInt(1)) + } else if let Ok(_) = input.try(|input| input.expect_ident_matching("off")) { + // off is an alias for '0' + Ok(FontSettingTagInt(0)) + } else { + // empty value is an alias for '1' + Ok(FontSettingTagInt(1)) + } + } +} + + +impl Parse for FontSettingTagFloat { + fn parse(_: &ParserContext, input: &mut Parser) -> Result { + input.expect_number().map(FontSettingTagFloat) + } +} + +impl ToCss for FontSettingTagFloat { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + dest.write_str(" ")?; + self.0.to_css(dest) + } +} + + diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 4c3adfc4d63..1311b7c7404 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -734,6 +734,12 @@ impl Percentage { pub fn parse_non_negative(input: &mut Parser) -> Result { Self::parse_with_clamping_mode(input, AllowedNumericType::NonNegative) } + + /// 100% + #[inline] + pub fn hundred() -> Self { + Percentage(1.) + } } impl Parse for Percentage { diff --git a/tests/unit/style/parsing/font.rs b/tests/unit/style/parsing/font.rs index 607f0ecb967..e092fd88989 100644 --- a/tests/unit/style/parsing/font.rs +++ b/tests/unit/style/parsing/font.rs @@ -5,8 +5,7 @@ use parsing::parse; use style::properties::longhands::{font_feature_settings, font_weight}; use style::properties::longhands::font_feature_settings::SpecifiedValue; -use style::properties::longhands::font_feature_settings::computed_value; -use style::properties::longhands::font_feature_settings::computed_value::FeatureTagValue; +use style::values::generics::{FontSettings, FontSettingTag, FontSettingTagInt}; use style_traits::ToCss; #[test] @@ -15,7 +14,7 @@ fn font_feature_settings_should_parse_properly() { use std::io::Cursor; let normal = parse_longhand!(font_feature_settings, "normal"); - let normal_computed = SpecifiedValue::Value(computed_value::T::Normal); + let normal_computed = SpecifiedValue::Value(FontSettings::Normal); assert_eq!(normal, normal_computed); let mut a_d_bytes = Cursor::new(b"abcd"); @@ -25,33 +24,33 @@ fn font_feature_settings_should_parse_properly() { let efgh = e_h_bytes.read_u32::().unwrap(); let on = parse_longhand!(font_feature_settings, "\"abcd\" on"); - let on_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ - FeatureTagValue { tag: abcd, value: 1 } + let on_computed = SpecifiedValue::Value(FontSettings::Tag(vec![ + FontSettingTag { tag: abcd, value: FontSettingTagInt(1) } ])); assert_eq!(on, on_computed); let off = parse_longhand!(font_feature_settings, "\"abcd\" off"); - let off_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ - FeatureTagValue { tag: abcd, value: 0 } + let off_computed = SpecifiedValue::Value(FontSettings::Tag(vec![ + FontSettingTag { tag: abcd, value: FontSettingTagInt(0) } ])); assert_eq!(off, off_computed); let no_value = parse_longhand!(font_feature_settings, "\"abcd\""); - let no_value_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ - FeatureTagValue { tag: abcd, value: 1 } + let no_value_computed = SpecifiedValue::Value(FontSettings::Tag(vec![ + FontSettingTag { tag: abcd, value: FontSettingTagInt(1) } ])); assert_eq!(no_value, no_value_computed); let pos_integer = parse_longhand!(font_feature_settings, "\"abcd\" 100"); - let pos_integer_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ - FeatureTagValue { tag: abcd, value: 100 } + let pos_integer_computed = SpecifiedValue::Value(FontSettings::Tag(vec![ + FontSettingTag { tag: abcd, value: FontSettingTagInt(100) } ])); assert_eq!(pos_integer, pos_integer_computed); let multiple = parse_longhand!(font_feature_settings, "\"abcd\" off, \"efgh\""); - let multiple_computed = SpecifiedValue::Value(computed_value::T::Tag(vec![ - FeatureTagValue { tag: abcd, value: 0 }, - FeatureTagValue { tag: efgh, value: 1 } + let multiple_computed = SpecifiedValue::Value(FontSettings::Tag(vec![ + FontSettingTag { tag: abcd, value: FontSettingTagInt(0) }, + FontSettingTag { tag: efgh, value: FontSettingTagInt(1) } ])); assert_eq!(multiple, multiple_computed); }