diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs index 58064f4f897..de60fe615be 100644 --- a/components/style/build_gecko.rs +++ b/components/style/build_gecko.rs @@ -502,7 +502,7 @@ mod bindings { .header(add_include("mozilla/ServoBindings.h")) .hide_type("nsACString_internal") .hide_type("nsAString_internal") - .raw_line("pub use nsstring::{nsACString, nsAString};") + .raw_line("pub use nsstring::{nsACString, nsAString, nsString};") .raw_line("type nsACString_internal = nsACString;") .raw_line("type nsAString_internal = nsAString;") .whitelisted_function("Servo_.*") @@ -584,6 +584,7 @@ mod bindings { "nsStyleVisibility", "nsStyleXUL", "nsTimingFunction", + "nscolor", "nscoord", "nsresult", "Loader", diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index 415bf710781..b0a043ead46 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -1,6 +1,6 @@ /* automatically generated by rust-bindgen */ -pub use nsstring::{nsACString, nsAString}; +pub use nsstring::{nsACString, nsAString, nsString}; type nsACString_internal = nsACString; type nsAString_internal = nsAString; use gecko_bindings::structs::mozilla::css::URLValue; @@ -159,6 +159,7 @@ use gecko_bindings::structs::nsStyleXUL; unsafe impl Send for nsStyleXUL {} unsafe impl Sync for nsStyleXUL {} use gecko_bindings::structs::nsTimingFunction; +use gecko_bindings::structs::nscolor; use gecko_bindings::structs::nscoord; use gecko_bindings::structs::nsresult; use gecko_bindings::structs::Loader; @@ -853,6 +854,14 @@ extern "C" { extern "C" { pub fn Gecko_PropertyId_IsPrefEnabled(id: nsCSSPropertyID) -> bool; } +extern "C" { + pub fn Gecko_nsStyleFont_SetLang(font: *mut nsStyleFont, + atom: *mut nsIAtom); +} +extern "C" { + pub fn Gecko_nsStyleFont_CopyLangFrom(aFont: *mut nsStyleFont, + aSource: *const nsStyleFont); +} extern "C" { pub fn Gecko_GetMediaFeatures() -> *const nsMediaFeature; } @@ -1440,11 +1449,67 @@ extern "C" { nsCSSPropertyID); } extern "C" { - pub fn Servo_DeclarationBlock_AddPresValue(declarations: + pub fn Servo_DeclarationBlock_PropertyIsSet(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID) + -> bool; +} +extern "C" { + pub fn Servo_DeclarationBlock_SetIdentStringValue(declarations: + RawServoDeclarationBlockBorrowed, + property: + nsCSSPropertyID, + value: *mut nsIAtom); +} +extern "C" { + pub fn Servo_DeclarationBlock_SetKeywordValue(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID, + value: i32); +} +extern "C" { + pub fn Servo_DeclarationBlock_SetIntValue(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID, + value: i32); +} +extern "C" { + pub fn Servo_DeclarationBlock_SetPixelValue(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID, + value: f32); +} +extern "C" { + pub fn Servo_DeclarationBlock_SetPercentValue(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID, + value: f32); +} +extern "C" { + pub fn Servo_DeclarationBlock_SetAutoValue(declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, - css_value: - nsCSSValueBorrowedMut); + property: nsCSSPropertyID); +} +extern "C" { + pub fn Servo_DeclarationBlock_SetCurrentColor(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID); +} +extern "C" { + pub fn Servo_DeclarationBlock_SetColorValue(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID, + value: nscolor); +} +extern "C" { + pub fn Servo_DeclarationBlock_SetFontFamily(declarations: + RawServoDeclarationBlockBorrowed, + value: + *const nsAString_internal); +} +extern "C" { + pub fn Servo_DeclarationBlock_SetTextDecorationColorOverride(declarations: + RawServoDeclarationBlockBorrowed); } extern "C" { pub fn Servo_CSSSupports2(name: *const nsACString_internal, diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 1219600a5d3..0b2debb233d 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -67,7 +67,7 @@ class Keyword(object): raise Exception("Bad product: " + product) def gecko_constant(self, value): - moz_stripped = value.replace("-moz-", '') if self.gecko_strip_moz_prefix else value + moz_stripped = value.replace("-moz-", '') if self.gecko_strip_moz_prefix else value.replace("-moz-", 'moz-') mapped = self.consts_map.get(value) if self.gecko_enum_prefix: parts = moz_stripped.split('-') diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs index e4b5b6be586..f9681e68361 100644 --- a/components/style/properties/declaration_block.rs +++ b/components/style/properties/declaration_block.rs @@ -40,6 +40,13 @@ impl Importance { } } +impl Default for Importance { + #[inline] + fn default() -> Self { + Importance::Normal + } +} + /// Overridden declarations are skipped. #[derive(Debug, PartialEq, Clone)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 6395bb4d10c..ca8dbd7a65e 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -33,6 +33,8 @@ use gecko_bindings::bindings::Gecko_FontFamilyList_Clear; use gecko_bindings::bindings::Gecko_SetCursorArrayLength; use gecko_bindings::bindings::Gecko_SetCursorImage; use gecko_bindings::bindings::Gecko_NewCSSShadowArray; +use gecko_bindings::bindings::Gecko_nsStyleFont_SetLang; +use gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom; use gecko_bindings::bindings::Gecko_SetListStyleImage; use gecko_bindings::bindings::Gecko_SetListStyleImageNone; use gecko_bindings::bindings::Gecko_SetListStyleType; @@ -53,7 +55,7 @@ use properties::longhands; use properties::{DeclaredValue, Importance, LonghandId}; use properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyDeclarationId}; use std::fmt::{self, Debug}; -use std::mem::{transmute, zeroed}; +use std::mem::{forget, transmute, zeroed}; use std::ptr; use std::sync::Arc; use std::cmp; @@ -233,8 +235,6 @@ def get_gecko_property(ffi_name, self_param = "self"): return "%s.gecko.%s" % (self_param, ffi_name) def set_gecko_property(ffi_name, expr): - if ffi_name == "__LIST_STYLE_TYPE__": - return "unsafe { Gecko_SetListStyleType(&mut self.gecko, %s as u32); }" % expr if "mBorderColor" in ffi_name: ffi_name = ffi_name.replace("mBorderColor", "*self.gecko.__bindgen_anon_1.mBorderColor.as_mut()") @@ -1121,7 +1121,7 @@ fn static_assert() { <%self:impl_trait style_struct_name="Font" - skip_longhands="font-family font-size font-size-adjust font-weight font-synthesis" + skip_longhands="font-family font-size font-size-adjust font-weight font-synthesis -x-lang" skip_additionals="*"> pub fn set_font_family(&mut self, v: longhands::font_family::computed_value::T) { @@ -1230,6 +1230,21 @@ fn static_assert() { } } + #[allow(non_snake_case)] + pub fn set__x_lang(&mut self, v: longhands::_x_lang::computed_value::T) { + let ptr = v.0.as_ptr(); + forget(v); + unsafe { + Gecko_nsStyleFont_SetLang(&mut self.gecko, ptr); + } + } + + #[allow(non_snake_case)] + pub fn copy__x_lang_from(&mut self, other: &Self) { + unsafe { + Gecko_nsStyleFont_CopyLangFrom(&mut self.gecko, &other.gecko); + } + } <%def name="impl_copy_animation_value(ident, gecko_ffi_name)"> @@ -2154,8 +2169,32 @@ fn static_assert() { unsafe { Gecko_CopyListStyleImageFrom(&mut self.gecko, &other.gecko); } } - ${impl_keyword_setter("list_style_type", "__LIST_STYLE_TYPE__", - data.longhands_by_name["list-style-type"].keyword)} + pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T) { + use properties::longhands::list_style_type::computed_value::T as Keyword; + <% + keyword = data.longhands_by_name["list-style-type"].keyword + # The first four are @counter-styles + # The rest have special fallback behavior + special = """upper-roman lower-roman upper-alpha lower-alpha + japanese-informal japanese-formal korean-hangul-formal korean-hanja-informal + korean-hanja-formal simp-chinese-informal simp-chinese-formal + trad-chinese-informal trad-chinese-formal""".split() + %> + let result = match v { + % for value in keyword.values_for('gecko'): + % if value in special: + // Special keywords are implemented as @counter-styles + // and need to be manually set as strings + Keyword::${to_rust_ident(value)} => structs::${keyword.gecko_constant("none")}, + % else: + Keyword::${to_rust_ident(value)} => + structs::${keyword.gecko_constant(value)}, + % endif + % endfor + }; + unsafe { Gecko_SetListStyleType(&mut self.gecko, result as u32); } + } + pub fn copy_list_style_type_from(&mut self, other: &Self) { unsafe { @@ -2208,6 +2247,15 @@ fn static_assert() { +<%self:impl_trait style_struct_name="Table" skip_longhands="-x-span"> + #[allow(non_snake_case)] + pub fn set__x_span(&mut self, v: longhands::_x_span::computed_value::T) { + self.gecko.mSpan = v.0 + } + + ${impl_simple_copy('_x_span', 'mSpan')} + + <%self:impl_trait style_struct_name="Effects" skip_longhands="box-shadow filter"> pub fn set_box_shadow(&mut self, v: longhands::box_shadow::computed_value::T) { @@ -2379,7 +2427,7 @@ fn static_assert() { -webkit-text-stroke-width text-emphasis-position -moz-tab-size"> <% text_align_keyword = Keyword("text-align", "start end left right center justify -moz-center -moz-left " + - "-moz-right match-parent") %> + "-moz-right match-parent char") %> ${impl_keyword('text_align', 'mTextAlign', text_align_keyword, need_clone=False)} pub fn set_text_shadow(&mut self, v: longhands::text_shadow::computed_value::T) { @@ -2579,6 +2627,9 @@ fn static_assert() { if v.contains(longhands::text_decoration_line::BLINK) { bits |= structs::NS_STYLE_TEXT_DECORATION_LINE_BLINK as u8; } + if v.contains(longhands::text_decoration_line::COLOR_OVERRIDE) { + bits |= structs::NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL as u8; + } self.gecko.mTextDecorationLine = bits; } diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index c9b26aa6489..a55e7e2b153 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -376,7 +376,44 @@ -<%def name="single_keyword_computed(name, values, vector=False, extra_specified=None, **kwargs)"> +<%def name="gecko_keyword_conversion(keyword, values=None, type='SpecifiedValue')"> + <% + if not values: + values = keyword.values_for(product) + %> + #[cfg(feature = "gecko")] + impl ${type} { + /// Obtain a specified value from a Gecko keyword value + /// + /// Intended for use with presentation attributes, not style structs + pub fn from_gecko_keyword(kw: u32) -> Self { + use gecko_bindings::structs; + % if keyword.gecko_enum_prefix: + % for value in values: + // We can't match on enum values if we're matching on a u32 + const ${to_rust_ident(value).upper()}: u32 + = structs::${keyword.gecko_enum_prefix}::${to_camel_case(value)} as u32; + % endfor + match kw { + % for value in values: + ${to_rust_ident(value).upper()} => ${type}::${to_rust_ident(value)}, + % endfor + x => panic!("Found unexpected value in style struct for ${keyword.name} property: {:?}", x), + } + % else: + match kw { + % for value in values: + structs::${keyword.gecko_constant(value)} => ${type}::${to_rust_ident(value)}, + % endfor + x => panic!("Found unexpected value in style struct for ${keyword.name} property: {:?}", x), + } + % endif + } + } + + +<%def name="single_keyword_computed(name, values, vector=False, + extra_specified=None, needs_conversion=False, **kwargs)"> <% keyword_kwargs = {a: kwargs.pop(a, None) for a in [ 'gecko_constant_prefix', 'gecko_enum_prefix', @@ -385,11 +422,11 @@ ]} %> - <%def name="inner_body()"> + <%def name="inner_body(keyword, extra_specified=None, needs_conversion=False)"> % if extra_specified: use style_traits::ToCss; define_css_keyword_enum! { SpecifiedValue: - % for value in data.longhands_by_name[name].keyword.values_for(product) + extra_specified.split(): + % for value in keyword.values_for(product) + extra_specified.split(): "${value}" => ${to_rust_ident(value)}, % endfor } @@ -424,15 +461,25 @@ SpecifiedValue::parse(input) } } + + % if needs_conversion: + <% + conversion_values = keyword.values_for(product) + if extra_specified: + conversion_values += extra_specified.split() + %> + ${gecko_keyword_conversion(keyword, values=conversion_values)} + % endif % if vector: <%call expr="vector_longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)"> - ${inner_body()} + ${inner_body(Keyword(name, values, **keyword_kwargs))} ${caller.body()} % else: <%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)"> - ${inner_body()} + ${inner_body(Keyword(name, values, **keyword_kwargs), + extra_specified=extra_specified, needs_conversion=needs_conversion)} ${caller.body()} % endif diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index 2b21214c391..7739eb4d9d2 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ <%namespace name="helpers" file="/helpers.mako.rs" /> -<% from data import Method, PHYSICAL_SIDES, ALL_SIDES, maybe_moz_logical_alias %> +<% from data import Keyword, Method, PHYSICAL_SIDES, ALL_SIDES, maybe_moz_logical_alias %> <% data.new_style_struct("Border", inherited=False, additional_methods=[Method("border_" + side + "_has_nonzero_width", @@ -32,6 +32,9 @@ animatable=False, logical = side[1])} % endfor +${helpers.gecko_keyword_conversion(Keyword('border-style', + "none solid double dotted dashed hidden groove ridge inset outset"), + type="::values::specified::BorderStyle")} % for side in ALL_SIDES: <%helpers:longhand name="border-${side[0]}-width" animatable="True" logical="${side[1]}" alias="${maybe_moz_logical_alias(product, side, '-moz-border-%s-width')}" diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 6cb2026b1d6..56ef26e603e 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ <%namespace name="helpers" file="/helpers.mako.rs" /> -<% from data import Keyword, Method, to_rust_ident %> +<% from data import Keyword, Method, to_rust_ident, to_camel_case%> <% data.new_style_struct("Box", inherited=False, @@ -93,6 +93,9 @@ } % endif + ${helpers.gecko_keyword_conversion(Keyword('display', ' '.join(values), + gecko_enum_prefix='StyleDisplay'))} + ${helpers.single_keyword("-moz-top-layer", "none top", @@ -146,6 +149,7 @@ ${helpers.single_keyword("-moz-top-layer", "none top", values="none left right" // https://drafts.csswg.org/css-logical-props/#float-clear extra_specified="inline-start inline-end" + needs_conversion="True" animatable="False" need_clone="True" gecko_enum_prefix="StyleFloat" @@ -190,6 +194,7 @@ ${helpers.single_keyword("-moz-top-layer", "none top", values="none left right both" // https://drafts.csswg.org/css-logical-props/#float-clear extra_specified="inline-start inline-end" + needs_conversion="True" animatable="False" gecko_enum_prefix="StyleClear" gecko_ffi_name="mBreakType" @@ -256,6 +261,8 @@ ${helpers.single_keyword("-moz-top-layer", "none top", extra_gecko_values="middle-with-baseline") %> <% vertical_align_keywords = vertical_align.keyword.values_for(product) %> + ${helpers.gecko_keyword_conversion(vertical_align.keyword)} + impl HasViewportPercentage for SpecifiedValue { fn has_viewport_percentage(&self) -> bool { match *self { diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index a52a7e1f498..a860e61ef8f 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -19,7 +19,7 @@ no_viewport_percentage!(SpecifiedValue); pub mod computed_value { - use cssparser::CssStringWriter; + use cssparser::{CssStringWriter, Parser}; use std::fmt::{self, Write}; use Atom; use style_traits::ToCss; @@ -73,6 +73,53 @@ } FontFamily::FamilyName(FamilyName(input)) } + + /// Parse a font-family value + pub fn parse(input: &mut Parser) -> Result { + if let Ok(value) = input.try(|input| input.expect_string()) { + return Ok(FontFamily::FamilyName(FamilyName(Atom::from(&*value)))) + } + let first_ident = try!(input.expect_ident()); + + // FIXME(bholley): The fast thing to do here would be to look up the + // string (as lowercase) in the static atoms table. We don't have an + // API to do that yet though, so we do the simple thing for now. + let mut css_wide_keyword = false; + match_ignore_ascii_case! { first_ident, + "serif" => return Ok(FontFamily::Generic(atom!("serif"))), + "sans-serif" => return Ok(FontFamily::Generic(atom!("sans-serif"))), + "cursive" => return Ok(FontFamily::Generic(atom!("cursive"))), + "fantasy" => return Ok(FontFamily::Generic(atom!("fantasy"))), + "monospace" => return Ok(FontFamily::Generic(atom!("monospace"))), + + // https://drafts.csswg.org/css-fonts/#propdef-font-family + // "Font family names that happen to be the same as a keyword value + // (`inherit`, `serif`, `sans-serif`, `monospace`, `fantasy`, and `cursive`) + // must be quoted to prevent confusion with the keywords with the same names. + // The keywords ‘initial’ and ‘default’ are reserved for future use + // and must also be quoted when used as font names. + // UAs must not consider these keywords as matching the type." + "inherit" => css_wide_keyword = true, + "initial" => css_wide_keyword = true, + "unset" => css_wide_keyword = true, + "default" => css_wide_keyword = true, + _ => {} + } + + let mut value = first_ident.into_owned(); + // These keywords are not allowed by themselves. + // The only way this value can be valid with with another keyword. + if css_wide_keyword { + let ident = input.expect_ident()?; + value.push_str(" "); + value.push_str(&ident); + } + while let Ok(ident) = input.try(|input| input.expect_ident()) { + value.push_str(" "); + value.push_str(&ident); + } + Ok(FontFamily::FamilyName(FamilyName(Atom::from(value)))) + } } impl ToCss for FamilyName { @@ -119,75 +166,27 @@ /// # /// = | [ + ] /// TODO: - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { - Vec::::parse(context, input).map(SpecifiedValue) + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result { + SpecifiedValue::parse(input) } - impl Parse for Vec { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { - input.parse_comma_separated(|input| FontFamily::parse(context, input)) + impl SpecifiedValue { + pub fn parse(input: &mut Parser) -> Result { + input.parse_comma_separated(|input| FontFamily::parse(input)).map(SpecifiedValue) } } /// `FamilyName::parse` is based on `FontFamily::parse` and not the other way around /// because we want the former to exclude generic family keywords. impl Parse for FamilyName { - fn parse(context: &ParserContext, input: &mut Parser) -> Result { - match FontFamily::parse(context, input) { + fn parse(_: &ParserContext, input: &mut Parser) -> Result { + match FontFamily::parse(input) { Ok(FontFamily::FamilyName(name)) => Ok(name), Ok(FontFamily::Generic(_)) | Err(()) => Err(()) } } } - - impl Parse for FontFamily { - fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - if let Ok(value) = input.try(|input| input.expect_string()) { - return Ok(FontFamily::FamilyName(FamilyName(Atom::from(&*value)))) - } - let first_ident = try!(input.expect_ident()); - - // FIXME(bholley): The fast thing to do here would be to look up the - // string (as lowercase) in the static atoms table. We don't have an - // API to do that yet though, so we do the simple thing for now. - let mut css_wide_keyword = false; - match_ignore_ascii_case! { first_ident, - "serif" => return Ok(FontFamily::Generic(atom!("serif"))), - "sans-serif" => return Ok(FontFamily::Generic(atom!("sans-serif"))), - "cursive" => return Ok(FontFamily::Generic(atom!("cursive"))), - "fantasy" => return Ok(FontFamily::Generic(atom!("fantasy"))), - "monospace" => return Ok(FontFamily::Generic(atom!("monospace"))), - - // https://drafts.csswg.org/css-fonts/#propdef-font-family - // "Font family names that happen to be the same as a keyword value - // (‘inherit’, ‘serif’, ‘sans-serif’, ‘monospace’, ‘fantasy’, and ‘cursive’) - // must be quoted to prevent confusion with the keywords with the same names. - // The keywords ‘initial’ and ‘default’ are reserved for future use - // and must also be quoted when used as font names. - // UAs must not consider these keywords as matching the type." - "inherit" => css_wide_keyword = true, - "initial" => css_wide_keyword = true, - "unset" => css_wide_keyword = true, - "default" => css_wide_keyword = true, - _ => {} - } - - let mut value = first_ident.into_owned(); - // These keywords are not allowed by themselves. - // The only way this value can be valid with with another keyword. - if css_wide_keyword { - let ident = input.expect_ident()?; - value.push_str(" "); - value.push_str(&ident); - } - while let Ok(ident) = input.try(|input| input.expect_ident()) { - value.push_str(" "); - value.push_str(&ident); - } - Ok(FontFamily::FamilyName(FamilyName(Atom::from(value)))) - } - } @@ -762,3 +761,40 @@ ${helpers.single_keyword("font-variant-position", } } + +<%helpers:longhand name="-x-lang" products="gecko" animatable="False" internal="True" + spec="Internal (not web-exposed)" + internal="True"> + use values::HasViewportPercentage; + use values::computed::ComputedValueAsSpecified; + pub use self::computed_value::T as SpecifiedValue; + + impl ComputedValueAsSpecified for SpecifiedValue {} + no_viewport_percentage!(SpecifiedValue); + + pub mod computed_value { + use Atom; + use std::fmt; + use style_traits::ToCss; + + impl ToCss for T { + fn to_css(&self, _: &mut W) -> fmt::Result where W: fmt::Write { + Ok(()) + } + } + + #[derive(Clone, Debug, PartialEq)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub struct T(pub Atom); + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(atom!("")) + } + + pub fn parse(_context: &ParserContext, _input: &mut Parser) -> Result { + debug_assert!(false, "Should be set directly by presentation attributes only."); + Err(()) + } + diff --git a/components/style/properties/longhand/inherited_table.mako.rs b/components/style/properties/longhand/inherited_table.mako.rs index 21930ed0114..1a6daa55417 100644 --- a/components/style/properties/longhand/inherited_table.mako.rs +++ b/components/style/properties/longhand/inherited_table.mako.rs @@ -16,6 +16,7 @@ ${helpers.single_keyword("empty-cells", "show hide", spec="https://drafts.csswg.org/css-tables/#propdef-empty-cells")} ${helpers.single_keyword("caption-side", "top bottom", extra_gecko_values="right left top-outside bottom-outside", + needs_conversion="True", animatable=False, spec="https://drafts.csswg.org/css-tables/#propdef-caption-side")} diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index 3d5430aee3e..60ca0ee5194 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ <%namespace name="helpers" file="/helpers.mako.rs" /> - +<% from data import Keyword %> <% data.new_style_struct("InheritedText", inherited=True, gecko_name="Text") %> <%helpers:longhand name="line-height" animatable="True" @@ -251,6 +251,7 @@ ${helpers.single_keyword("text-align-last", _moz_left("-moz-left") => 7, _moz_right("-moz-right") => 8, match_parent("match-parent") => 9, + char("char") => 10, % endif } } @@ -260,6 +261,10 @@ ${helpers.single_keyword("text-align-last", pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { computed_value::T::parse(input) } + ${helpers.gecko_keyword_conversion(Keyword('text-align', + """left right center justify -moz-left -moz-right + -moz-center char end match-parent""", + gecko_strip_moz_prefix=False))} // FIXME: This prop should be animatable. @@ -515,6 +520,7 @@ ${helpers.single_keyword("text-align-last", <%helpers:single_keyword_computed name="white-space" values="normal pre nowrap pre-wrap pre-line" gecko_constant_prefix="NS_STYLE_WHITESPACE" + needs_conversion="True" animatable="False" spec="https://drafts.csswg.org/css-text/#propdef-white-space"> use values::computed::ComputedValueAsSpecified; diff --git a/components/style/properties/longhand/list.mako.rs b/components/style/properties/longhand/list.mako.rs index a5a1c30861a..5f1bf103d7f 100644 --- a/components/style/properties/longhand/list.mako.rs +++ b/components/style/properties/longhand/list.mako.rs @@ -16,15 +16,24 @@ ${helpers.single_keyword("list-style-position", "outside inside", animatable=Fal // // TODO(bholley): Missing quite a few gecko properties here as well. // +// In gecko, {upper,lower}-{roman,alpha} are implemented as @counter-styles in the +// UA, however they can also be set from pres attrs. When @counter-style is supported +// we may need to look into this and handle these differently. +// // [1]: http://dev.w3.org/csswg/css-counter-styles/ ${helpers.single_keyword("list-style-type", """ - disc none circle square decimal disclosure-open disclosure-closed + disc none circle square decimal disclosure-open disclosure-closed lower-alpha upper-alpha """, extra_servo_values="""arabic-indic bengali cambodian cjk-decimal devanagari gujarati gurmukhi kannada khmer lao malayalam mongolian myanmar oriya persian telugu thai tibetan cjk-earthly-branch cjk-heavenly-stem lower-greek hiragana hiragana-iroha katakana - katakana-iroha lower-alpha upper-alpha""", + katakana-iroha""", + extra_gecko_values="""japanese-informal japanese-formal korean-hangul-formal + korean-hanja-formal korean-hanja-informal simp-chinese-informal simp-chinese-formal + trad-chinese-informal trad-chinese-formal ethiopic-numeric upper-roman lower-roman + """, gecko_constant_prefix="NS_STYLE_LIST_STYLE", + needs_conversion="True", animatable=False, spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type")} diff --git a/components/style/properties/longhand/pointing.mako.rs b/components/style/properties/longhand/pointing.mako.rs index a6219a32d1f..b661ec457eb 100644 --- a/components/style/properties/longhand/pointing.mako.rs +++ b/components/style/properties/longhand/pointing.mako.rs @@ -159,7 +159,7 @@ ${helpers.single_keyword("-moz-user-input", "auto none enabled disabled", ${helpers.single_keyword("-moz-user-modify", "read-only read-write write-only", products="gecko", gecko_ffi_name="mUserModify", gecko_enum_prefix="StyleUserModify", - gecko_inexhaustive=True, + needs_conversion=True, animatable=False, spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-modify)")} diff --git a/components/style/properties/longhand/table.mako.rs b/components/style/properties/longhand/table.mako.rs index 36e2216ef62..c145dde146c 100644 --- a/components/style/properties/longhand/table.mako.rs +++ b/components/style/properties/longhand/table.mako.rs @@ -9,3 +9,39 @@ ${helpers.single_keyword("table-layout", "auto fixed", gecko_ffi_name="mLayoutStrategy", animatable=False, spec="https://drafts.csswg.org/css-tables/#propdef-table-layout")} + +<%helpers:longhand name="-x-span" products="gecko" + spec="Internal-only (for `` pres attr)" + animatable="False" + internal="True"> + use values::HasViewportPercentage; + use values::computed::ComputedValueAsSpecified; + + impl ComputedValueAsSpecified for SpecifiedValue {} + no_viewport_percentage!(SpecifiedValue); + pub type SpecifiedValue = computed_value::T; + pub mod computed_value { + use std::fmt; + use style_traits::ToCss; + + #[derive(PartialEq, Clone, Copy, Debug)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub struct T(pub i32); + + impl ToCss for T { + fn to_css(&self, _: &mut W) -> fmt::Result where W: fmt::Write { + Ok(()) + } + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T(1) + } + + // never parse it, only set via presentation attribute + fn parse(_: &ParserContext, _: &mut Parser) -> Result { + Err(()) + } + diff --git a/components/style/properties/longhand/text.mako.rs b/components/style/properties/longhand/text.mako.rs index abc5bc05f27..cfd4b26fa3c 100644 --- a/components/style/properties/longhand/text.mako.rs +++ b/components/style/properties/longhand/text.mako.rs @@ -122,6 +122,16 @@ ${helpers.single_keyword("unicode-bidi", const UNDERLINE = 0x02, const LINE_THROUGH = 0x04, const BLINK = 0x08, + % if product == "gecko": + /// Only set by presentation attributes + /// + /// Setting this will mean that text-decorations use the color + /// specified by `color` in quirks mode. + /// + /// For example, this gives text + /// a red text decoration + const COLOR_OVERRIDE = 0x10, + % endif } } diff --git a/components/style/properties/shorthand/font.mako.rs b/components/style/properties/shorthand/font.mako.rs index 1bcf2c10616..2a89e461ad0 100644 --- a/components/style/properties/shorthand/font.mako.rs +++ b/components/style/properties/shorthand/font.mako.rs @@ -12,10 +12,9 @@ ${'font-variant-position' if product == 'gecko' else ''} ${'font-language-override' if product == 'none' else ''}" spec="https://drafts.csswg.org/css-fonts-3/#propdef-font"> - use parser::Parse; use properties::longhands::{font_style, font_variant, font_weight, font_stretch}; - use properties::longhands::{font_size, line_height, font_family}; - use properties::longhands::font_family::computed_value::FontFamily; + use properties::longhands::{font_size, line_height}; + use properties::longhands::font_family::SpecifiedValue as FontFamily; pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result { let mut nb_normals = 0; @@ -71,7 +70,7 @@ } else { None }; - let family = Vec::::parse(context, input)?; + let family = FontFamily::parse(input)?; Ok(Longhands { font_style: style, font_variant: variant, @@ -79,7 +78,7 @@ font_stretch: stretch, font_size: size, line_height: line_height, - font_family: Some(font_family::SpecifiedValue(family)), + font_family: Some(family), % if product == "gecko": font_size_adjust: None, font_kerning: None, diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index d2e64481a39..0c41e6518c7 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -368,6 +368,13 @@ pub enum Length { Calc(Box, AllowedNumericType), } +impl From for Length { + #[inline] + fn from(len: NoCalcLength) -> Self { + Length::NoCalc(len) + } +} + impl HasViewportPercentage for Length { fn has_viewport_percentage(&self) -> bool { match *self { @@ -938,6 +945,20 @@ impl From for LengthOrPercentage { } } +impl From for LengthOrPercentage { + #[inline] + fn from(len: NoCalcLength) -> Self { + LengthOrPercentage::Length(len) + } +} + +impl From for LengthOrPercentage { + #[inline] + fn from(pc: Percentage) -> Self { + LengthOrPercentage::Percentage(pc) + } +} + impl HasViewportPercentage for LengthOrPercentage { fn has_viewport_percentage(&self) -> bool { match *self { @@ -1043,6 +1064,21 @@ pub enum LengthOrPercentageOrAuto { Calc(Box), } + +impl From for LengthOrPercentageOrAuto { + #[inline] + fn from(len: NoCalcLength) -> Self { + LengthOrPercentageOrAuto::Length(len) + } +} + +impl From for LengthOrPercentageOrAuto { + #[inline] + fn from(pc: Percentage) -> Self { + LengthOrPercentageOrAuto::Percentage(pc) + } +} + impl HasViewportPercentage for LengthOrPercentageOrAuto { fn has_viewport_percentage(&self) -> bool { match *self { diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index a61dcf52370..5964aa3a2f2 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -36,7 +36,7 @@ use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSet use style::gecko_bindings::bindings::{RawServoStyleSheetBorrowed, ServoComputedValuesBorrowed}; use style::gecko_bindings::bindings::{RawServoStyleSheetStrong, ServoComputedValuesStrong}; use style::gecko_bindings::bindings::{ServoCssRulesBorrowed, ServoCssRulesStrong}; -use style::gecko_bindings::bindings::{nsACString, nsCSSValueBorrowedMut, nsAString}; +use style::gecko_bindings::bindings::{nsACString, nsAString}; use style::gecko_bindings::bindings::Gecko_AnimationAppendKeyframe; use style::gecko_bindings::bindings::RawGeckoAnimationValueListBorrowedMut; use style::gecko_bindings::bindings::RawGeckoElementBorrowed; @@ -952,59 +952,277 @@ pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(declarations: RawSer remove_property(declarations, get_property_id_from_nscsspropertyid!(property, ())) } +macro_rules! get_longhand_from_id { + ($id:expr, $retval:expr) => { + match PropertyId::from_nscsspropertyid($id) { + Ok(PropertyId::Longhand(long)) => long, + _ => { + error!("stylo: unknown presentation property with id {:?}", $id); + return $retval + } + } + }; + ($id:expr) => { + get_longhand_from_id!($id, ()) + } +} + +macro_rules! match_wrap_declared { + ($longhand:ident, $($property:ident => $inner:expr,)*) => ( + match $longhand { + $( + LonghandId::$property => PropertyDeclaration::$property(DeclaredValue::Value($inner)), + )* + _ => { + error!("stylo: Don't know how to handle presentation property {:?}", $longhand); + return + } + } + ) +} + #[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_AddPresValue(declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, - css_value: nsCSSValueBorrowedMut) { - use style::gecko::values::convert_nscolor_to_rgba; - use style::properties::{DeclaredValue, LonghandId, PropertyDeclaration, PropertyId, longhands}; - use style::values::specified; +pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID) + -> bool { + use style::properties::PropertyDeclarationId; + let declarations = RwLock::::as_arc(&declarations); + let long = get_longhand_from_id!(property, false); + declarations.read().get(PropertyDeclarationId::Longhand(long)).is_some() +} + +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(declarations: + RawServoDeclarationBlockBorrowed, + property: + nsCSSPropertyID, + value: + *mut nsIAtom) { + use style::properties::{DeclaredValue, PropertyDeclaration, LonghandId}; + use style::properties::longhands::_x_lang::computed_value::T as Lang; let declarations = RwLock::::as_arc(&declarations); - let prop = PropertyId::from_nscsspropertyid(property); - - let long = match prop { - Ok(PropertyId::Longhand(long)) => long, - _ => { - warn!("stylo: unknown presentation property with id {:?}", property); - return - } + let long = get_longhand_from_id!(property); + let prop = match_wrap_declared! { long, + XLang => Lang(Atom::from(value)), }; - let decl = match long { - LonghandId::FontSize => { - if let Some(int) = css_value.integer() { - PropertyDeclaration::FontSize(DeclaredValue::Value( - longhands::font_size::SpecifiedValue( - specified::LengthOrPercentage::Length( - specified::NoCalcLength::from_font_size_int(int as u8) - ) - ) - )) - } else { - warn!("stylo: got unexpected non-integer value for font-size presentation attribute"); - return - } - } - LonghandId::Color => { - if let Some(color) = css_value.color_value() { - PropertyDeclaration::Color(DeclaredValue::Value( - specified::CSSRGBA { - parsed: convert_nscolor_to_rgba(color), - authored: None - } - )) - } else { - warn!("stylo: got unexpected non-integer value for color presentation attribute"); - return - } - } - _ => { - warn!("stylo: cannot handle longhand {:?} from presentation attribute", long); - return - } - }; - declarations.write().declarations.push((decl, Importance::Normal)); + declarations.write().declarations.push((prop, Default::default())); +} +#[no_mangle] +#[allow(unreachable_code)] +pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID, + value: i32) { + use style::properties::{DeclaredValue, PropertyDeclaration, LonghandId}; + use style::properties::longhands; + use style::values::specified::{BorderStyle, NoCalcLength}; + + let declarations = RwLock::::as_arc(&declarations); + let long = get_longhand_from_id!(property); + let value = value as u32; + + let prop = match_wrap_declared! { long, + MozUserModify => longhands::_moz_user_modify::SpecifiedValue::from_gecko_keyword(value), + // TextEmphasisPosition => FIXME implement text-emphasis-position + Display => longhands::display::SpecifiedValue::from_gecko_keyword(value), + Float => longhands::float::SpecifiedValue::from_gecko_keyword(value), + VerticalAlign => longhands::vertical_align::SpecifiedValue::from_gecko_keyword(value), + TextAlign => longhands::text_align::SpecifiedValue::from_gecko_keyword(value), + Clear => longhands::clear::SpecifiedValue::from_gecko_keyword(value), + FontSize => { + // We rely on Gecko passing in font-size values (0...7) here. + longhands::font_size::SpecifiedValue(NoCalcLength::from_font_size_int(value as u8).into()) + }, + ListStyleType => longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value), + WhiteSpace => longhands::white_space::SpecifiedValue::from_gecko_keyword(value), + CaptionSide => longhands::caption_side::SpecifiedValue::from_gecko_keyword(value), + BorderTopStyle => BorderStyle::from_gecko_keyword(value), + BorderRightStyle => BorderStyle::from_gecko_keyword(value), + BorderBottomStyle => BorderStyle::from_gecko_keyword(value), + BorderLeftStyle => BorderStyle::from_gecko_keyword(value), + }; + declarations.write().declarations.push((prop, Default::default())); +} + +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SetIntValue(declarations: RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID, + value: i32) { + use style::properties::{DeclaredValue, PropertyDeclaration, LonghandId}; + use style::properties::longhands::_x_span::computed_value::T as Span; + + let declarations = RwLock::::as_arc(&declarations); + let long = get_longhand_from_id!(property); + let prop = match_wrap_declared! { long, + XSpan => Span(value), + }; + declarations.write().declarations.push((prop, Default::default())); +} + +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID, + value: f32) { + use style::properties::{DeclaredValue, PropertyDeclaration, LonghandId}; + use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing; + use style::values::specified::BorderWidth; + use style::values::specified::length::NoCalcLength; + + let declarations = RwLock::::as_arc(&declarations); + let long = get_longhand_from_id!(property); + let nocalc = NoCalcLength::from_px(value); + + let prop = match_wrap_declared! { long, + Height => nocalc.into(), + Width => nocalc.into(), + BorderTopWidth => BorderWidth::Width(nocalc.into()), + BorderRightWidth => BorderWidth::Width(nocalc.into()), + BorderBottomWidth => BorderWidth::Width(nocalc.into()), + BorderLeftWidth => BorderWidth::Width(nocalc.into()), + MarginTop => nocalc.into(), + MarginRight => nocalc.into(), + MarginBottom => nocalc.into(), + MarginLeft => nocalc.into(), + PaddingTop => nocalc.into(), + PaddingRight => nocalc.into(), + PaddingBottom => nocalc.into(), + PaddingLeft => nocalc.into(), + BorderSpacing => Box::new( + BorderSpacing { + horizontal: nocalc.into(), + vertical: nocalc.into(), + } + ), + }; + declarations.write().declarations.push((prop, Default::default())); +} + +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID, + value: f32) { + use style::properties::{DeclaredValue, PropertyDeclaration, LonghandId}; + use style::values::specified::length::Percentage; + + let declarations = RwLock::::as_arc(&declarations); + let long = get_longhand_from_id!(property); + let pc = Percentage(value); + + let prop = match_wrap_declared! { long, + Height => pc.into(), + Width => pc.into(), + MarginTop => pc.into(), + MarginRight => pc.into(), + MarginBottom => pc.into(), + MarginLeft => pc.into(), + }; + declarations.write().declarations.push((prop, Default::default())); +} + +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID) { + use style::properties::{DeclaredValue, PropertyDeclaration, LonghandId}; + use style::values::specified::LengthOrPercentageOrAuto; + + let declarations = RwLock::::as_arc(&declarations); + let long = get_longhand_from_id!(property); + let auto = LengthOrPercentageOrAuto::Auto; + + let prop = match_wrap_declared! { long, + Height => auto, + Width => auto, + MarginTop => auto, + MarginRight => auto, + MarginBottom => auto, + MarginLeft => auto, + }; + declarations.write().declarations.push((prop, Default::default())); +} + +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID) { + use cssparser::Color; + use style::properties::{DeclaredValue, PropertyDeclaration, LonghandId}; + use style::values::specified::CSSColor; + + let declarations = RwLock::::as_arc(&declarations); + let long = get_longhand_from_id!(property); + let cc = CSSColor { parsed: Color::CurrentColor, authored: None }; + + let prop = match_wrap_declared! { long, + BorderTopColor => cc, + BorderRightColor => cc, + BorderBottomColor => cc, + BorderLeftColor => cc, + }; + declarations.write().declarations.push((prop, Default::default())); +} + +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations: + RawServoDeclarationBlockBorrowed, + property: nsCSSPropertyID, + value: structs::nscolor) { + use cssparser::Color; + use style::gecko::values::convert_nscolor_to_rgba; + use style::properties::{DeclaredValue, PropertyDeclaration, LonghandId}; + use style::values::specified::{CSSColor, CSSRGBA}; + + let declarations = RwLock::::as_arc(&declarations); + let long = get_longhand_from_id!(property); + let rgba = convert_nscolor_to_rgba(value); + let color = CSSColor { parsed: Color::RGBA(rgba), authored: None }; + + let prop = match_wrap_declared! { long, + BorderTopColor => color, + BorderRightColor => color, + BorderBottomColor => color, + BorderLeftColor => color, + Color => CSSRGBA { parsed: rgba, authored: None }, + BackgroundColor => color, + }; + declarations.write().declarations.push((prop, Default::default())); +} + +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(declarations: + RawServoDeclarationBlockBorrowed, + value: *const nsAString) { + use cssparser::Parser; + use style::properties::{DeclaredValue, PropertyDeclaration}; + use style::properties::longhands::font_family::SpecifiedValue as FontFamily; + + let declarations = RwLock::::as_arc(&declarations); + let string = unsafe { (*value).to_string() }; + let mut parser = Parser::new(&string); + if let Ok(family) = FontFamily::parse(&mut parser) { + if parser.is_exhausted() { + let decl = PropertyDeclaration::FontFamily(DeclaredValue::Value(family)); + declarations.write().declarations.push((decl, Default::default())); + } + } +} + +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(declarations: + RawServoDeclarationBlockBorrowed) { + use style::properties::{DeclaredValue, PropertyDeclaration}; + use style::properties::longhands::text_decoration_line; + + let declarations = RwLock::::as_arc(&declarations); + let mut decoration = text_decoration_line::computed_value::none; + decoration |= text_decoration_line::COLOR_OVERRIDE; + let decl = PropertyDeclaration::TextDecorationLine(DeclaredValue::Value(decoration)); + declarations.write().declarations.push((decl, Default::default())); } #[no_mangle]