From c63a9a37a9a52e15d03700b2695f3c79f69e3351 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Tue, 24 Jul 2018 16:50:47 +0900 Subject: [PATCH 01/23] style: Introduce nsCSSKeywordAndBoolTableEntry. The values in the boolean context depend on its feature. For examples, in the case of prefers-reduced-motion 'no-preference' means false and 'reduced' mean true in the boolean context, whereas in the case of prefers-contrast 'no-preference' means false and other two values, 'high' and 'low' means true in the boolean context. To support it we introduce a child struct of nsCSSKTableEntry that has an additional field representing the value in the boolean context and use it when we have no specified value in the media feature (i.e. in the boolean context). Bug: 1365045 Reviewed-by: heycam MozReview-Commit-ID: 79HiW8l5ous --- components/style/gecko/media_queries.rs | 162 +++++++++++++++++++----- 1 file changed, 127 insertions(+), 35 deletions(-) diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 9c5ef4d71a1..221281ba404 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -16,6 +16,7 @@ use gecko_bindings::structs; use gecko_bindings::structs::{nsCSSKTableEntry, nsCSSKeyword, nsCSSUnit, nsCSSValue}; use gecko_bindings::structs::{nsMediaFeature, nsMediaFeature_RangeType}; use gecko_bindings::structs::{nsMediaFeature_ValueType, nsPresContext}; +use gecko_bindings::structs::nsCSSKeywordAndBoolTableEntry; use gecko_bindings::structs::RawGeckoPresContextOwned; use media_queries::MediaType; use parser::{Parse, ParserContext}; @@ -374,6 +375,9 @@ pub enum MediaExpressionValue { /// An enumerated value, defined by the variant keyword table in the /// feature's `mData` member. Enumerated(i16), + /// Similar to the above Enumerated but the variant keyword table has an + /// additional field what the keyword value means in the Boolean Context. + BoolEnumerated(i16), /// An identifier. Ident(Atom), } @@ -420,6 +424,10 @@ impl MediaExpressionValue { let value = css_value.integer_unchecked() as i16; Some(MediaExpressionValue::Enumerated(value)) }, + nsMediaFeature_ValueType::eBoolEnumerated => { + let value = css_value.integer_unchecked() as i16; + Some(MediaExpressionValue::BoolEnumerated(value)) + }, nsMediaFeature_ValueType::eIdent => { debug_assert_eq!(css_value.mUnit, nsCSSUnit::eCSSUnit_AtomIdent); Some(MediaExpressionValue::Ident(unsafe { @@ -457,25 +465,43 @@ impl MediaExpressionValue { MediaExpressionValue::Resolution(ref r) => r.to_css(dest), MediaExpressionValue::Ident(ref ident) => serialize_atom_identifier(ident, dest), MediaExpressionValue::Enumerated(value) => unsafe { - use std::{slice, str}; - use std::os::raw::c_char; - - // NB: All the keywords on nsMediaFeatures are static, - // well-formed utf-8. - let mut length = 0; - - let (keyword, _value) = find_in_table( + let keyword = find_in_table( *for_expr.feature.mData.mKeywordTable.as_ref(), |_kw, val| val == value, + |e| e.keyword(), ).expect("Value not found in the keyword table?"); - let buffer: *const c_char = bindings::Gecko_CSSKeywordString(keyword, &mut length); - let buffer = slice::from_raw_parts(buffer as *const u8, length as usize); - - let string = str::from_utf8_unchecked(buffer); - - dest.write_str(string) + MediaExpressionValue::keyword_to_css(keyword, dest) }, + MediaExpressionValue::BoolEnumerated(value) => unsafe { + let keyword = find_in_table( + *for_expr.feature.mData.mKeywordAndBoolTable.as_ref(), + |_kw, val| val == value, + |e| e.keyword(), + ).expect("Value not found in the keyword table?"); + + MediaExpressionValue::keyword_to_css(keyword, dest) + } + } + } + + fn keyword_to_css(keyword: nsCSSKeyword, dest: &mut CssWriter) -> fmt::Result + where + W: fmt::Write, + { + use std::{slice, str}; + use std::os::raw::c_char; + + // NB: All the keywords on nsMediaFeatures are static, + // well-formed utf-8. + let mut length = 0; + unsafe { + let buffer: *const c_char = bindings::Gecko_CSSKeywordString(keyword, &mut length); + let buffer = slice::from_raw_parts(buffer as *const u8, length as usize); + + let string = str::from_utf8_unchecked(buffer); + + dest.write_str(string) } } } @@ -496,23 +522,51 @@ where None } -unsafe fn find_in_table( - mut current_entry: *const nsCSSKTableEntry, - mut f: F, -) -> Option<(nsCSSKeyword, i16)> +trait TableEntry { + fn value(&self) -> i16; + fn keyword(&self) -> nsCSSKeyword; +} + +impl TableEntry for nsCSSKTableEntry { + fn value(&self) -> i16 { + self.mValue + } + fn keyword(&self) -> nsCSSKeyword { + self.mKeyword + } +} + +impl TableEntry for nsCSSKeywordAndBoolTableEntry { + fn value(&self) -> i16 { + self._base.mValue + } + fn keyword(&self) -> nsCSSKeyword { + self._base.mKeyword + } +} + +unsafe fn find_in_table( + current_entry: *const T, + find: FindFunc, + result_func: ResultFunc, +) -> Option where - F: FnMut(nsCSSKeyword, i16) -> bool, + T: TableEntry, + FindFunc: Fn(nsCSSKeyword, i16) -> bool, + ResultFunc: Fn(&T) -> R, { + let mut current_entry = current_entry; + loop { - let value = (*current_entry).mValue; - let keyword = (*current_entry).mKeyword; + let value = (*current_entry).value(); + let keyword = (*current_entry).keyword(); if value == -1 { return None; // End of the table. } - if f(keyword, value) { - return Some((keyword, value)); + if find(keyword, value) { + return Some(result_func(&*current_entry)); } current_entry = current_entry.offset(1); @@ -556,24 +610,21 @@ fn parse_feature_value<'i, 't>( MediaExpressionValue::Resolution(Resolution::parse(context, input)?) }, nsMediaFeature_ValueType::eEnumerated => { - let location = input.current_source_location(); - let keyword = input.expect_ident()?; - let keyword = unsafe { - bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), keyword.len() as u32) - }; - let first_table_entry: *const nsCSSKTableEntry = unsafe { *feature.mData.mKeywordTable.as_ref() }; - let value = match unsafe { find_in_table(first_table_entry, |kw, _| kw == keyword) } { - Some((_kw, value)) => value, - None => { - return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)) - }, - }; + let value = parse_keyword(input, first_table_entry)?; MediaExpressionValue::Enumerated(value) }, + nsMediaFeature_ValueType::eBoolEnumerated => { + let first_table_entry: *const nsCSSKeywordAndBoolTableEntry = + unsafe { *feature.mData.mKeywordAndBoolTable.as_ref() }; + + let value = parse_keyword(input, first_table_entry)?; + + MediaExpressionValue::BoolEnumerated(value) + }, nsMediaFeature_ValueType::eIdent => { MediaExpressionValue::Ident(Atom::from(input.expect_ident()?.as_ref())) }, @@ -582,6 +633,30 @@ fn parse_feature_value<'i, 't>( Ok(value) } +/// Parse a keyword and returns the corresponding i16 value. +fn parse_keyword<'i, 't, T>( + input: &mut Parser<'i, 't>, + first_table_entry: *const T, +) -> Result> +where + T: TableEntry, +{ + let location = input.current_source_location(); + let keyword = input.expect_ident()?; + let keyword = unsafe { + bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), keyword.len() as u32) + }; + + let value = unsafe { + find_in_table(first_table_entry, |kw, _| kw == keyword, |e| e.value()) + }; + + match value { + Some(value) => Ok(value), + None => Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)), + } +} + /// Consumes an operation or a colon, or returns an error. fn consume_operation_or_colon( input: &mut Parser, @@ -834,6 +909,16 @@ impl MediaFeatureExpression { quirks_mode, |context| l.to_computed_value(&context).px() != 0., ), + BoolEnumerated(value) => { + let value = unsafe { + find_in_table( + *self.feature.mData.mKeywordAndBoolTable.as_ref(), + |_kw, val| val == value, + |e| e.mValueInBooleanContext, + ) + }; + value.expect("Value not found in the keyword table?") + }, _ => true, }; }, @@ -880,6 +965,13 @@ impl MediaFeatureExpression { ); return one == other; }, + (&BoolEnumerated(one), &BoolEnumerated(other)) => { + debug_assert_ne!( + self.feature.mRangeType, + nsMediaFeature_RangeType::eMinMaxAllowed + ); + return one == other; + }, _ => unreachable!(), }; From 798d45f38d5379800dc12ddf15e4652884c3eee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 25 Jul 2018 13:15:21 +0200 Subject: [PATCH 02/23] style: Generate StyleDisplay using cbindgen. We use the same setup WR uses, which is checking-in the files. But I think it's much better than keeping the two things in sync manually :) When you add a new value, you need to add it to the rust source, then run the command, but since it doesn't need to build the style crate (it uses the Rust AST, doesn't build) there's no problem. Differential Revision: https://phabricator.services.mozilla.com/D2354 --- components/style/cbindgen.toml | 26 +++++++++++++ components/style/properties/gecko.mako.rs | 46 +++++++---------------- components/style/values/specified/box.rs | 35 +++++++++++------ 3 files changed, 63 insertions(+), 44 deletions(-) create mode 100644 components/style/cbindgen.toml diff --git a/components/style/cbindgen.toml b/components/style/cbindgen.toml new file mode 100644 index 00000000000..ff4fe642a90 --- /dev/null +++ b/components/style/cbindgen.toml @@ -0,0 +1,26 @@ +header = """/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */""" +autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen. + * To generate this file: + * 1. Get the latest cbindgen using `cargo install --force cbindgen` + * a. Alternatively, you can clone `https://github.com/eqrion/cbindgen` and use a tagged release + * 2. Run `rustup run nightly cbindgen toolkit/library/rust/ --lockfile Cargo.lock --crate style -o layout/style/ServoStyleConsts.h` + */""" +include_version = true +braces = "SameLine" +line_length = 80 +tab_width = 2 +language = "C++" +namespaces = ["mozilla"] + +[struct] +derive_eq = true + +[enum] +derive_helper_methods = true + +[export] +prefix = "Style" +include = ["StyleDisplay"] +item_types = ["enums"] diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index c91ef4d4476..62a4eb86819 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -3031,57 +3031,39 @@ fn static_assert() { shape-outside contain touch-action translate scale""" %> <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}"> - - // We manually-implement the |display| property until we get general - // infrastructure for preffing certain values. - <% display_keyword = Keyword("display", "inline block inline-block table inline-table table-row-group " + - "table-header-group table-footer-group table-row table-column-group " + - "table-column table-cell table-caption list-item flex none " + - "inline-flex grid inline-grid ruby ruby-base ruby-base-container " + - "ruby-text ruby-text-container contents flow-root -webkit-box " + - "-webkit-inline-box -moz-box -moz-inline-box -moz-grid -moz-inline-grid " + - "-moz-grid-group -moz-grid-line -moz-stack -moz-inline-stack -moz-deck " + - "-moz-popup -moz-groupbox", - gecko_enum_prefix="StyleDisplay", - gecko_strip_moz_prefix=False) %> - - fn match_display_keyword( - v: longhands::display::computed_value::T - ) -> structs::root::mozilla::StyleDisplay { - use properties::longhands::display::computed_value::T as Keyword; - // FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts - match v { - % for value in display_keyword.values_for('gecko'): - Keyword::${to_camel_case(value)} => - structs::${display_keyword.gecko_constant(value)}, - % endfor - } - } - + #[inline] pub fn set_display(&mut self, v: longhands::display::computed_value::T) { - let result = Self::match_display_keyword(v); - self.gecko.mDisplay = result; - self.gecko.mOriginalDisplay = result; + // unsafe: cbindgen ensures the representation is the same. + self.gecko.mDisplay = unsafe { transmute(v) }; + self.gecko.mOriginalDisplay = unsafe { transmute(v) }; } + #[inline] pub fn copy_display_from(&mut self, other: &Self) { self.gecko.mDisplay = other.gecko.mDisplay; self.gecko.mOriginalDisplay = other.gecko.mDisplay; } + #[inline] pub fn reset_display(&mut self, other: &Self) { self.copy_display_from(other) } + #[inline] pub fn set_adjusted_display( &mut self, v: longhands::display::computed_value::T, _is_item_or_root: bool ) { - self.gecko.mDisplay = Self::match_display_keyword(v); + // unsafe: cbindgen ensures the representation is the same. + self.gecko.mDisplay = unsafe { transmute(v) }; } - <%call expr="impl_keyword_clone('display', 'mDisplay', display_keyword)"> + #[inline] + pub fn clone_display(&self) -> longhands::display::computed_value::T { + // unsafe: cbindgen ensures the representation is the same. + unsafe { transmute(self.gecko.mDisplay) } + } <% float_keyword = Keyword("float", "Left Right None", gecko_enum_prefix="StyleFloat") %> ${impl_keyword('float', 'mFloat', float_keyword)} diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index cec7c8ccc33..de53bb20262 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -41,29 +41,42 @@ fn moz_box_display_values_enabled(context: &ParserContext) -> bool { } } +/// Defines an element’s display type, which consists of +/// the two basic qualities of how an element generates boxes +/// +/// +/// +/// NOTE(emilio): Order is important in Gecko! +/// +/// If you change it, make sure to take a look at the +/// FrameConstructionDataByDisplay stuff (both the XUL and non-XUL version), and +/// ensure it's still correct! +/// +/// Also, when you change this from Gecko you may need to regenerate the +/// C++-side bindings (see components/style/cbindgen.toml). #[allow(missing_docs)] #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] -/// Defines an element’s display type, which consists of -/// the two basic qualities of how an element generates boxes -/// +#[repr(u8)] pub enum Display { - Inline, + None = 0, Block, + #[cfg(feature = "gecko")] + FlowRoot, + Inline, InlineBlock, + ListItem, Table, InlineTable, TableRowGroup, + TableColumn, + TableColumnGroup, TableHeaderGroup, TableFooterGroup, TableRow, - TableColumnGroup, - TableColumn, TableCell, TableCaption, - ListItem, - None, #[parse(aliases = "-webkit-flex")] Flex, #[parse(aliases = "-webkit-inline-flex")] @@ -85,8 +98,6 @@ pub enum Display { #[cfg(feature = "gecko")] Contents, #[cfg(feature = "gecko")] - FlowRoot, - #[cfg(feature = "gecko")] WebkitBox, #[cfg(feature = "gecko")] WebkitInlineBox, @@ -119,10 +130,10 @@ pub enum Display { MozDeck, #[cfg(feature = "gecko")] #[parse(condition = "moz_display_values_enabled")] - MozPopup, + MozGroupbox, #[cfg(feature = "gecko")] #[parse(condition = "moz_display_values_enabled")] - MozGroupbox, + MozPopup, } impl Display { From 0cab212052a09ccb595917fe914e54e56be0bbdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 25 Jul 2018 15:03:45 +0200 Subject: [PATCH 03/23] style: Autogenerate StyleAppearance. This builds on bug 1428676 and introduces StyleAppearance, which replaces the NS_THEME_* constants. Really sorry for the size of the patch. There's a non-trivial change in the gtk theme, which I submitted separately as bug 1478385. Differential Revision: https://phabricator.services.mozilla.com/D2361 --- components/style/cbindgen.toml | 2 +- components/style/properties/gecko.mako.rs | 32 ++- .../style/properties/longhands/box.mako.rs | 45 +--- components/style/values/computed/box.rs | 2 +- components/style/values/computed/mod.rs | 2 +- components/style/values/specified/box.rs | 246 ++++++++++++++++++ components/style/values/specified/mod.rs | 2 +- 7 files changed, 291 insertions(+), 40 deletions(-) diff --git a/components/style/cbindgen.toml b/components/style/cbindgen.toml index ff4fe642a90..86c3dddec4c 100644 --- a/components/style/cbindgen.toml +++ b/components/style/cbindgen.toml @@ -22,5 +22,5 @@ derive_helper_methods = true [export] prefix = "Style" -include = ["StyleDisplay"] +include = ["StyleDisplay", "StyleAppearance"] item_types = ["enums"] diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 62a4eb86819..312f43878ae 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -368,6 +368,34 @@ def set_gecko_property(ffi_name, expr): return "self.gecko.%s = %s;" % (ffi_name, expr) %> +<%def name="impl_cbindgen_keyword(ident, gecko_ffi_name)"> + #[allow(non_snake_case)] + #[inline] + pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { + // unsafe: cbindgen ensures the representations match. + ${set_gecko_property(gecko_ffi_name, "unsafe { transmute(v) }")} + } + + #[allow(non_snake_case)] + #[inline] + pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { + // unsafe: cbindgen ensures the representations match. + unsafe { transmute(${get_gecko_property(gecko_ffi_name)}) } + } + + #[allow(non_snake_case)] + #[inline] + pub fn copy_${ident}_from(&mut self, other: &Self) { + self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}; + } + + #[allow(non_snake_case)] + #[inline] + pub fn reset_${ident}(&mut self, other: &Self) { + self.copy_${ident}_from(other) + } + + <%def name="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type='u8', on_set=None)"> #[allow(non_snake_case)] pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { @@ -3015,7 +3043,7 @@ fn static_assert() { } -<% skip_box_longhands= """display overflow-y vertical-align +<% skip_box_longhands= """display -moz-appearance overflow-y vertical-align animation-name animation-delay animation-duration animation-direction animation-fill-mode animation-play-state animation-iteration-count animation-timing-function @@ -3065,6 +3093,8 @@ fn static_assert() { unsafe { transmute(self.gecko.mDisplay) } } + ${impl_cbindgen_keyword('_moz_appearance', 'mAppearance')} + <% float_keyword = Keyword("float", "Left Right None", gecko_enum_prefix="StyleFloat") %> ${impl_keyword('float', 'mFloat', float_keyword)} diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index 627b9a8ce3a..ed08ac8504a 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -508,41 +508,16 @@ ${helpers.predefined_type("contain", spec="https://drafts.csswg.org/css-contain/#contain-property")} // Non-standard -${helpers.single_keyword("-moz-appearance", - """none button button-arrow-down button-arrow-next button-arrow-previous button-arrow-up - button-bevel button-focus caret checkbox checkbox-container checkbox-label checkmenuitem - dialog dualbutton groupbox inner-spin-button listbox listitem menuarrow menubar menucheckbox - menuimage menuitem menuitemtext menulist menulist-button menulist-text menulist-textfield - menupopup menuradio menuseparator meterbar meterchunk number-input progressbar - progressbar-vertical progresschunk progresschunk-vertical radio radio-container radio-label - radiomenuitem range range-thumb resizer resizerpanel scale-horizontal scalethumbend - scalethumb-horizontal scalethumbstart scalethumbtick scalethumb-vertical scale-vertical - scrollbar scrollbar-horizontal scrollbar-small scrollbar-vertical scrollbarbutton-down - scrollbarbutton-left scrollbarbutton-right scrollbarbutton-up scrollbarthumb-horizontal - scrollbarthumb-vertical scrollbartrack-horizontal scrollbartrack-vertical scrollcorner - searchfield separator - spinner spinner-downbutton spinner-textfield spinner-upbutton splitter statusbar - statusbarpanel tab tabpanel tabpanels tab-scroll-arrow-back tab-scroll-arrow-forward - textfield textfield-multiline toolbar toolbarbutton toolbarbutton-dropdown toolbargripper - toolbox tooltip treeheader treeheadercell treeheadersortarrow treeitem treeline treetwisty - treetwistyopen treeview window - -moz-gtk-info-bar -moz-mac-active-source-list-selection -moz-mac-disclosure-button-closed - -moz-mac-disclosure-button-open -moz-mac-fullscreen-button -moz-mac-help-button - -moz-mac-source-list -moz-mac-source-list-selection -moz-mac-vibrancy-dark - -moz-mac-vibrancy-light -moz-mac-vibrant-titlebar-light -moz-mac-vibrant-titlebar-dark - -moz-win-borderless-glass -moz-win-browsertabbar-toolbox - -moz-win-communications-toolbox -moz-win-exclude-glass -moz-win-glass -moz-win-media-toolbox - -moz-window-button-box -moz-window-button-box-maximized -moz-window-button-close - -moz-window-button-maximize -moz-window-button-minimize -moz-window-button-restore - -moz-window-frame-bottom -moz-window-frame-left -moz-window-frame-right -moz-window-titlebar - -moz-window-titlebar-maximized - """, - gecko_ffi_name="mAppearance", - gecko_constant_prefix="ThemeWidgetType_NS_THEME", - products="gecko", - alias="-webkit-appearance:layout.css.webkit-appearance.enabled", - spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance)", - animation_value_type="discrete")} +${helpers.predefined_type( + "-moz-appearance", + "Appearance", + "computed::Appearance::None", + products="gecko", + alias="-webkit-appearance:layout.css.webkit-appearance.enabled", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance)", + needs_context=False, + animation_value_type="discrete", +)} ${helpers.predefined_type("-moz-binding", "url::UrlOrNone", "computed::url::UrlOrNone::none()", products="gecko", diff --git a/components/style/values/computed/box.rs b/components/style/values/computed/box.rs index f5c101cbc38..b0db8337608 100644 --- a/components/style/values/computed/box.rs +++ b/components/style/values/computed/box.rs @@ -10,7 +10,7 @@ use values::generics::box_::AnimationIterationCount as GenericAnimationIteration use values::generics::box_::Perspective as GenericPerspective; use values::generics::box_::VerticalAlign as GenericVerticalAlign; -pub use values::specified::box_::{AnimationName, Contain, Display, OverflowClipBox}; +pub use values::specified::box_::{AnimationName, Appearance, Contain, Display, OverflowClipBox}; pub use values::specified::box_::{Clear as SpecifiedClear, Float as SpecifiedFloat}; pub use values::specified::box_::{OverscrollBehavior, ScrollSnapType, TouchAction, TransitionProperty, WillChange}; diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 14a74a4ed53..fa2a9cdcf0d 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -43,7 +43,7 @@ pub use self::font::{FontFamily, FontLanguageOverride, FontStyle, FontVariantEas pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric}; pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display, TransitionProperty}; -pub use self::box_::{Clear, Float}; +pub use self::box_::{Appearance, Clear, Float}; pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective}; pub use self::box_::{ScrollSnapType, TouchAction, VerticalAlign, WillChange}; pub use self::color::{Color, ColorPropertyValue, RGBAColor}; diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index de53bb20262..5f34ef91884 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -881,3 +881,249 @@ pub enum Clear { InlineStart, InlineEnd } + +/// The value for the `appearance` property. +/// +/// https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance +/// +/// NOTE(emilio): When changing this you may want to regenerate the C++ bindings +/// (see components/style/cbindgen.toml) +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, + SpecifiedValueInfo, ToCss, ToComputedValue)] +#[repr(u8)] +pub enum Appearance { + /// No appearance at all. + None, + /// A typical dialog button. + Button, + /// Various arrows that go in buttons + ButtonArrowDown, + ButtonArrowNext, + ButtonArrowPrevious, + ButtonArrowUp, + /// A rectangular button that contains complex content + /// like images (e.g. HTML