diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 072413995b2f..856f8dbc52e1 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -1847,6 +1847,10 @@ where node.type_id() ); + // FIXME(emilio): This should look at display-outside and + // display-inside, but there's so much stuff that goes through the + // generic "block" codepath (wrongly). + // // Switch on display and floatedness. match (display, float, positioning) { // `display: none` contributes no flow construction result. @@ -1871,12 +1875,6 @@ where self.set_flow_construction_result(node, construction_result) }, - // List items contribute their own special flows. - (Display::ListItem, float_value, _) => { - let construction_result = self.build_flow_for_list_item(node, float_value); - self.set_flow_construction_result(node, construction_result) - }, - // Inline items that are absolutely-positioned contribute inline fragment construction // results with a hypothetical fragment. (Display::Inline, _, Position::Absolute) | @@ -1958,7 +1956,12 @@ where // properties separately. (_, float_value, _) => { let float_kind = FloatKind::from_property(float_value); - let construction_result = self.build_flow_for_block(node, float_kind); + // List items contribute their own special flows. + let construction_result = if display.is_list_item() { + self.build_flow_for_list_item(node, float_value) + } else { + self.build_flow_for_block(node, float_kind) + }; self.set_flow_construction_result(node, construction_result) }, } diff --git a/components/layout/generated_content.rs b/components/layout/generated_content.rs index 683bb316897f..d69ddd659911 100644 --- a/components/layout/generated_content.rs +++ b/components/layout/generated_content.rs @@ -19,7 +19,6 @@ use crate::traversal::InorderFlowTraversal; use script_layout_interface::wrapper_traits::PseudoElementType; use smallvec::SmallVec; use std::collections::{HashMap, LinkedList}; -use style::computed_values::display::T as Display; use style::computed_values::list_style_type::T as ListStyleType; use style::properties::ComputedValues; use style::selector_parser::RestyleDamage; @@ -175,7 +174,7 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> { } let mut list_style_type = fragment.style().get_list().list_style_type; - if fragment.style().get_box().display != Display::ListItem { + if !fragment.style().get_box().display.is_list_item() { list_style_type = ListStyleType::None } @@ -291,7 +290,7 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> { fn reset_and_increment_counters_as_necessary(&mut self, fragment: &mut Fragment) { let mut list_style_type = fragment.style().get_list().list_style_type; - if !self.is_block || fragment.style().get_box().display != Display::ListItem { + if !self.is_block || !fragment.style().get_box().display.is_list_item() { list_style_type = ListStyleType::None } diff --git a/components/style/font_face.rs b/components/style/font_face.rs index 50814c5f5e8b..d45cd340c858 100644 --- a/components/style/font_face.rs +++ b/components/style/font_face.rs @@ -414,16 +414,10 @@ impl Parse for Source { macro_rules! is_descriptor_enabled { ("font-display") => { - unsafe { - use crate::gecko_bindings::structs::mozilla; - mozilla::StaticPrefs::sVarCache_layout_css_font_display_enabled - } + static_prefs::pref!("layout.css.font-display.enabled") }; ("font-variation-settings") => { - unsafe { - use crate::gecko_bindings::structs::mozilla; - mozilla::StaticPrefs::sVarCache_layout_css_font_variations_enabled != 0 - } + static_prefs::pref!("layout.css.font-variations.enabled") }; ($name:tt) => { true diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 556470569dba..bb126e16948f 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -213,12 +213,11 @@ impl Device { None => return MediaType::screen(), }; - // Gecko allows emulating random media with mIsEmulatingMedia and - // mMediaEmulated. - let medium_to_use = if pc.mIsEmulatingMedia() != 0 { - pc.mMediaEmulated.mRawPtr + // Gecko allows emulating random media with mMediaEmulationData.mMedium. + let medium_to_use = if !pc.mMediaEmulationData.mMedium.mRawPtr.is_null() { + pc.mMediaEmulationData.mMedium.mRawPtr } else { - pc.mMedium + pc.mMedium as *const structs::nsAtom as *mut _ }; MediaType(CustomIdent(unsafe { Atom::from_raw(medium_to_use) })) @@ -253,9 +252,8 @@ impl Device { None => return Scale::new(1.), }; - let override_dppx = pc.mOverrideDPPX; - if override_dppx > 0.0 { - return Scale::new(override_dppx); + if pc.mMediaEmulationData.mDPPX > 0.0 { + return Scale::new(pc.mMediaEmulationData.mDPPX); } let au_per_dpx = pc.mCurAppUnitsPerDevPixel as f32; @@ -270,8 +268,7 @@ impl Device { if doc.mIsBeingUsedAsImage() { return true; } - let document_color_use = - unsafe { structs::StaticPrefs::sVarCache_browser_display_document_color_use }; + let document_color_use = static_prefs::pref!("browser.display.document_color_use"); let prefs = self.pref_sheet_prefs(); match document_color_use { 1 => true, diff --git a/components/style/gecko/pseudo_element.rs b/components/style/gecko/pseudo_element.rs index 501611830ffd..aa849ceee024 100644 --- a/components/style/gecko/pseudo_element.rs +++ b/components/style/gecko/pseudo_element.rs @@ -187,9 +187,7 @@ impl PseudoElement { PseudoElement::FirstLine => PropertyFlags::APPLIES_TO_FIRST_LINE, PseudoElement::Placeholder => PropertyFlags::APPLIES_TO_PLACEHOLDER, PseudoElement::Cue => PropertyFlags::APPLIES_TO_CUE, - PseudoElement::Marker - if unsafe { structs::StaticPrefs::sVarCache_layout_css_marker_restricted } => - { + PseudoElement::Marker if static_prefs::pref!("layout.css.marker.restricted") => { PropertyFlags::APPLIES_TO_MARKER }, _ => return None, diff --git a/components/style/gecko/pseudo_element_definition.mako.rs b/components/style/gecko/pseudo_element_definition.mako.rs index 562b4c184444..d8d80d601652 100644 --- a/components/style/gecko/pseudo_element_definition.mako.rs +++ b/components/style/gecko/pseudo_element_definition.mako.rs @@ -112,7 +112,7 @@ impl PseudoElement { % for pseudo in PSEUDOS: ${pseudo_element_variant(pseudo)} => % if pseudo.is_tree_pseudo_element(): - if unsafe { structs::StaticPrefs::sVarCache_layout_css_xul_tree_pseudos_content_enabled } { + if static_prefs::pref!("layout.css.xul-tree-pseudos.content.enabled") { 0 } else { structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME @@ -209,9 +209,7 @@ impl PseudoElement { if starts_with_ignore_ascii_case(name, "-moz-tree-") { return PseudoElement::tree_pseudo_element(name, Box::new([])) } - if unsafe { - structs::StaticPrefs::sVarCache_layout_css_unknown_webkit_pseudo_element - } { + if static_prefs::pref!("layout.css.unknown-webkit-pseudo-element") { const WEBKIT_PREFIX: &str = "-webkit-"; if starts_with_ignore_ascii_case(name, WEBKIT_PREFIX) { let part = string_as_ascii_lowercase(&name[WEBKIT_PREFIX.len()..]); diff --git a/components/style/gecko/selector_parser.rs b/components/style/gecko/selector_parser.rs index 1da352249d4c..2aad41adc9c0 100644 --- a/components/style/gecko/selector_parser.rs +++ b/components/style/gecko/selector_parser.rs @@ -5,7 +5,7 @@ //! Gecko-specific bits for selector-parsing. use crate::element_state::{DocumentState, ElementState}; -use crate::gecko_bindings::structs::{self, RawServoSelectorList}; +use crate::gecko_bindings::structs::RawServoSelectorList; use crate::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; use crate::invalidation::element::document_state::InvalidationMatchingData; use crate::selector_parser::{Direction, SelectorParser}; @@ -170,13 +170,10 @@ impl NonTSPseudoClass { /// Returns whether the pseudo-class is enabled in content sheets. fn is_enabled_in_content(&self) -> bool { - use crate::gecko_bindings::structs::mozilla; match *self { // For pseudo-classes with pref, the availability in content // depends on the pref. - NonTSPseudoClass::Fullscreen => unsafe { - mozilla::StaticPrefs::sVarCache_full_screen_api_unprefix_enabled - }, + NonTSPseudoClass::Fullscreen => static_prefs::pref!("full-screen-api.unprefix.enabled"), // Otherwise, a pseudo-class is enabled in content when it // doesn't have any enabled flag. _ => !self @@ -354,8 +351,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> { #[inline] fn parse_part(&self) -> bool { - self.chrome_rules_enabled() || - unsafe { structs::StaticPrefs::sVarCache_layout_css_shadow_parts_enabled } + self.chrome_rules_enabled() || static_prefs::pref!("layout.css.shadow-parts.enabled") } fn parse_non_ts_pseudo_class( diff --git a/components/style/lib.rs b/components/style/lib.rs index 587b926efc6c..35070b0f2546 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -91,6 +91,8 @@ extern crate servo_config; extern crate servo_url; extern crate smallbitvec; extern crate smallvec; +#[cfg(feature = "gecko")] +extern crate static_prefs; #[cfg(feature = "servo")] extern crate string_cache; #[macro_use] diff --git a/components/style/media_queries/media_feature_expression.rs b/components/style/media_queries/media_feature_expression.rs index 310cbd2b8bbc..98c7d59c7e14 100644 --- a/components/style/media_queries/media_feature_expression.rs +++ b/components/style/media_queries/media_feature_expression.rs @@ -11,8 +11,6 @@ use super::Device; use crate::context::QuirksMode; #[cfg(feature = "gecko")] use crate::gecko::media_features::MEDIA_FEATURES; -#[cfg(feature = "gecko")] -use crate::gecko_bindings::structs; use crate::parser::{Parse, ParserContext}; #[cfg(feature = "servo")] use crate::servo::media_queries::MEDIA_FEATURES; @@ -301,9 +299,7 @@ impl MediaFeatureExpression { if starts_with_ignore_ascii_case(feature_name, "-webkit-") { feature_name = &feature_name[8..]; requirements.insert(ParsingRequirements::WEBKIT_PREFIX); - if unsafe { - structs::StaticPrefs::sVarCache_layout_css_prefixes_device_pixel_ratio_webkit - } { + if static_prefs::pref!("layout.css.prefixes.device-pixel-ratio-webkit") { requirements.insert( ParsingRequirements::WEBKIT_DEVICE_PIXEL_RATIO_PREF_ENABLED, ); diff --git a/components/style/properties/cascade.rs b/components/style/properties/cascade.rs index c3ce242eadd2..da95840a08ac 100644 --- a/components/style/properties/cascade.rs +++ b/components/style/properties/cascade.rs @@ -673,7 +673,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { #[inline] #[cfg(feature = "gecko")] fn recompute_default_font_family_type_if_needed(&mut self) { - use crate::gecko_bindings::{bindings, structs}; + use crate::gecko_bindings::bindings; use crate::values::computed::font::GenericFontFamily; if !self.seen.contains(LonghandId::XLang) && @@ -681,7 +681,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> { return; } - let use_document_fonts = unsafe { structs::StaticPrefs::sVarCache_browser_display_use_document_fonts != 0 }; + let use_document_fonts = static_prefs::pref!("browser.display.use_document_fonts") != 0; let builder = &mut self.context.builder; let (default_font_type, prioritize_user_fonts) = { let font = builder.get_font().gecko(); diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 46cb724e11df..d1e78e6648c2 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -652,9 +652,6 @@ def _remove_common_first_line_and_first_letter_properties(props, engine): props.remove("text-emphasis-position") props.remove("text-emphasis-style") props.remove("text-emphasis-color") - props.remove("text-decoration-skip-ink") - props.remove("text-decoration-thickness") - props.remove("text-underline-offset") props.remove("overflow-wrap") props.remove("text-align") diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index f00e5aafced2..1f3e862df495 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -973,11 +973,10 @@ fn static_assert() { <% skip_position_longhands = " ".join(x.ident for x in SIDES) %> <%self:impl_trait style_struct_name="Position" - skip_longhands="${skip_position_longhands} order + skip_longhands="${skip_position_longhands} align-content justify-content align-self justify-self align-items justify-items - grid-auto-flow grid-template-rows - grid-template-columns"> + grid-auto-flow"> % for side in SIDES: <% impl_split_style_coord(side.ident, "mOffset", side.index) %> % endfor @@ -1015,226 +1014,6 @@ fn static_assert() { } } - pub fn set_order(&mut self, v: longhands::order::computed_value::T) { - self.gecko.mOrder = v; - } - - pub fn clone_order(&self) -> longhands::order::computed_value::T { - self.gecko.mOrder - } - - ${impl_simple_copy('order', 'mOrder')} - - % for kind in ["rows", "columns"]: - pub fn set_grid_template_${kind}(&mut self, v: longhands::grid_template_${kind}::computed_value::T) { - <% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %> - use crate::gecko_bindings::structs::nsTArray; - use std::usize; - use crate::values::CustomIdent; - use crate::values::generics::grid::TrackListType::Auto; - use crate::values::generics::grid::{GridTemplateComponent, RepeatCount, TrackListValue, MAX_GRID_LINE}; - - #[inline] - fn set_line_names(servo_names: &[CustomIdent], gecko_names: &mut nsTArray>) { - unsafe { - bindings::Gecko_ResizeAtomArray(gecko_names, servo_names.len() as u32); - } - - for (servo_name, gecko_name) in servo_names.iter().zip(gecko_names.iter_mut()) { - gecko_name.set_move(unsafe { - RefPtr::from_addrefed(servo_name.0.clone().into_addrefed()) - }); - } - } - - let max_lines = MAX_GRID_LINE as usize - 1; // for accounting the final - - let result = match v { - GridTemplateComponent::None => ptr::null_mut(), - GridTemplateComponent::TrackList(track) => { - let mut num_values = track.values.len(); - if let Auto(_) = track.list_type { - num_values += 1; - } - - num_values = cmp::min(num_values, max_lines); - let value = unsafe { - bindings::Gecko_CreateStyleGridTemplate(num_values as u32, - (num_values + 1) as u32).as_mut().unwrap() - }; - - let mut auto_idx = usize::MAX; - let mut auto_track_size = None; - if let Auto(idx) = track.list_type { - auto_idx = idx as usize; - let auto_repeat = track.auto_repeat.as_ref().expect("expected value"); - - if auto_repeat.count == RepeatCount::AutoFill { - value.set_mIsAutoFill(true); - } - - value.mRepeatAutoIndex = idx as i16; - // NOTE: Gecko supports only one set of values in - // i.e., it can only take repeat(auto-fill, [a] 10px [b]), and no more. - set_line_names(&auto_repeat.line_names[0], &mut value.mRepeatAutoLineNameListBefore); - set_line_names(&auto_repeat.line_names[1], &mut value.mRepeatAutoLineNameListAfter); - auto_track_size = Some(auto_repeat.track_sizes.get(0).unwrap().clone()); - } else { - unsafe { - bindings::Gecko_ResizeAtomArray( - &mut value.mRepeatAutoLineNameListBefore, 0); - bindings::Gecko_ResizeAtomArray( - &mut value.mRepeatAutoLineNameListAfter, 0); - } - } - - let mut line_names = track.line_names.into_iter(); - let mut values_iter = track.values.into_iter(); - { - for (i, track_size) in value.mTrackSizingFunctions.iter_mut().enumerate().take(max_lines) { - let name_list = line_names.next().expect("expected line-names"); - set_line_names(&name_list, &mut value.mLineNameLists[i]); - *track_size = if i == auto_idx { - auto_track_size.take().expect("expected for ") - } else { - match values_iter.next().expect("expected value") { - TrackListValue::TrackSize(size) => size, - // FIXME(emilio): This shouldn't be - // representable in the first place. - TrackListValue::TrackRepeat(..) => { - unreachable!("Shouldn't have track-repeats in computed track lists") - } - } - }; - } - } - - let final_names = line_names.next().unwrap(); - set_line_names(&final_names, value.mLineNameLists.last_mut().unwrap()); - - value - }, - GridTemplateComponent::Subgrid(list) => { - let names_length = match list.fill_idx { - Some(_) => list.names.len() - 1, - None => list.names.len(), - }; - let num_values = cmp::min(names_length, max_lines + 1); - let value = unsafe { - bindings::Gecko_CreateStyleGridTemplate(0, num_values as u32).as_mut().unwrap() - }; - value.set_mIsSubgrid(true); - - let mut names = list.names.into_vec(); - if let Some(idx) = list.fill_idx { - value.set_mIsAutoFill(true); - value.mRepeatAutoIndex = idx as i16; - set_line_names(&names.swap_remove(idx as usize), - &mut value.mRepeatAutoLineNameListBefore); - } - - for (servo_names, gecko_names) in names.iter().zip(value.mLineNameLists.iter_mut()) { - set_line_names(servo_names, gecko_names); - } - - value - }, - }; - - unsafe { bindings::Gecko_SetStyleGridTemplate(&mut ${self_grid}, result); } - } - - pub fn copy_grid_template_${kind}_from(&mut self, other: &Self) { - unsafe { - bindings::Gecko_CopyStyleGridTemplateValues(&mut ${self_grid}, - other.gecko.mGridTemplate${kind.title()}.mPtr); - } - } - - pub fn reset_grid_template_${kind}(&mut self, other: &Self) { - self.copy_grid_template_${kind}_from(other) - } - - pub fn clone_grid_template_${kind}(&self) -> longhands::grid_template_${kind}::computed_value::T { - <% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %> - use crate::gecko_bindings::structs::nsTArray; - use crate::values::CustomIdent; - use crate::values::generics::grid::{GridTemplateComponent, LineNameList, RepeatCount}; - use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue, TrackRepeat}; - - let value = match unsafe { ${self_grid}.mPtr.as_ref() } { - None => return GridTemplateComponent::None, - Some(value) => value, - }; - - #[inline] - fn to_boxed_customident_slice(gecko_names: &nsTArray>) -> Box<[CustomIdent]> { - let idents: Vec = gecko_names.iter().map(|gecko_name| { - CustomIdent(unsafe { Atom::from_raw(gecko_name.mRawPtr) }) - }).collect(); - idents.into_boxed_slice() - } - - #[inline] - fn to_line_names_vec( - gecko_line_names: &nsTArray>>, - ) -> Vec> { - gecko_line_names.iter().map(|gecko_names| { - to_boxed_customident_slice(gecko_names) - }).collect() - } - - let repeat_auto_index = value.mRepeatAutoIndex as usize; - if value.mIsSubgrid() { - let mut names_vec = to_line_names_vec(&value.mLineNameLists); - let fill_idx = if value.mIsAutoFill() { - names_vec.insert( - repeat_auto_index, - to_boxed_customident_slice(&value.mRepeatAutoLineNameListBefore)); - Some(repeat_auto_index as u32) - } else { - None - }; - let names = names_vec.into_boxed_slice(); - - GridTemplateComponent::Subgrid(LineNameList{names, fill_idx}) - } else { - let mut auto_repeat = None; - let mut list_type = TrackListType::Normal; - let line_names = to_line_names_vec(&value.mLineNameLists).into_boxed_slice(); - let mut values = Vec::with_capacity(value.mTrackSizingFunctions.len()); - for (i, track_size) in value.mTrackSizingFunctions.iter().enumerate() { - if i == repeat_auto_index { - list_type = TrackListType::Auto(repeat_auto_index as u16); - - let count = if value.mIsAutoFill() { - RepeatCount::AutoFill - } else { - RepeatCount::AutoFit - }; - - let line_names = { - let mut vec: Vec> = Vec::with_capacity(2); - vec.push(to_boxed_customident_slice( - &value.mRepeatAutoLineNameListBefore)); - vec.push(to_boxed_customident_slice( - &value.mRepeatAutoLineNameListAfter)); - vec.into_boxed_slice() - }; - - let track_sizes = vec!(track_size.clone()); - - auto_repeat = Some(TrackRepeat{count, line_names, track_sizes}); - } else { - values.push(TrackListValue::TrackSize(track_size.clone())); - } - } - - GridTemplateComponent::TrackList(TrackList{list_type, values, line_names, auto_repeat}) - } - } - % endfor - ${impl_simple_type_with_conversion("grid_auto_flow")} @@ -2799,97 +2578,15 @@ fn static_assert() { <%self:impl_trait style_struct_name="InheritedText" - skip_longhands="text-align text-emphasis-style - -webkit-text-stroke-width text-emphasis-position"> + skip_longhands="text-align -webkit-text-stroke-width text-emphasis-position"> <% text_align_keyword = Keyword("text-align", "start end left right center justify -moz-center -moz-left -moz-right char", gecko_strip_moz_prefix=False) %> ${impl_keyword('text_align', 'mTextAlign', text_align_keyword)} - fn clear_text_emphasis_style_if_string(&mut self) { - if self.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 { - self.gecko.mTextEmphasisStyleString.truncate(); - self.gecko.mTextEmphasisStyle = structs::NS_STYLE_TEXT_EMPHASIS_STYLE_NONE as u8; - } - } - ${impl_simple_type_with_conversion("text_emphasis_position")} - pub fn set_text_emphasis_style(&mut self, v: values::computed::TextEmphasisStyle) { - use crate::values::computed::TextEmphasisStyle; - use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword}; - - self.clear_text_emphasis_style_if_string(); - let (te, s) = match v { - TextEmphasisStyle::None => (structs::NS_STYLE_TEXT_EMPHASIS_STYLE_NONE, ""), - TextEmphasisStyle::Keyword(ref keyword) => { - let fill = match keyword.fill { - TextEmphasisFillMode::Filled => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_FILLED, - TextEmphasisFillMode::Open => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_OPEN, - }; - let shape = match keyword.shape { - TextEmphasisShapeKeyword::Dot => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_DOT, - TextEmphasisShapeKeyword::Circle => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_CIRCLE, - TextEmphasisShapeKeyword::DoubleCircle => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_DOUBLE_CIRCLE, - TextEmphasisShapeKeyword::Triangle => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_TRIANGLE, - TextEmphasisShapeKeyword::Sesame => structs::NS_STYLE_TEXT_EMPHASIS_STYLE_SESAME, - }; - - (shape | fill, keyword.shape.char(keyword.fill)) - }, - TextEmphasisStyle::String(ref s) => { - (structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING, &**s) - }, - }; - self.gecko.mTextEmphasisStyleString.assign_str(s); - self.gecko.mTextEmphasisStyle = te as u8; - } - - pub fn copy_text_emphasis_style_from(&mut self, other: &Self) { - self.clear_text_emphasis_style_if_string(); - if other.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 { - self.gecko.mTextEmphasisStyleString - .assign(&*other.gecko.mTextEmphasisStyleString) - } - self.gecko.mTextEmphasisStyle = other.gecko.mTextEmphasisStyle; - } - - pub fn reset_text_emphasis_style(&mut self, other: &Self) { - self.copy_text_emphasis_style_from(other) - } - - pub fn clone_text_emphasis_style(&self) -> values::computed::TextEmphasisStyle { - use crate::values::computed::TextEmphasisStyle; - use crate::values::computed::text::TextEmphasisKeywordValue; - use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword}; - - if self.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_NONE as u8 { - return TextEmphasisStyle::None; - } - - if self.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 { - return TextEmphasisStyle::String(self.gecko.mTextEmphasisStyleString.to_string()); - } - - let fill = - self.gecko.mTextEmphasisStyle & structs::NS_STYLE_TEXT_EMPHASIS_STYLE_OPEN as u8 == 0; - - let fill = if fill { TextEmphasisFillMode::Filled } else { TextEmphasisFillMode::Open }; - - let shape = - match self.gecko.mTextEmphasisStyle as u32 & !structs::NS_STYLE_TEXT_EMPHASIS_STYLE_OPEN { - structs::NS_STYLE_TEXT_EMPHASIS_STYLE_DOT => TextEmphasisShapeKeyword::Dot, - structs::NS_STYLE_TEXT_EMPHASIS_STYLE_CIRCLE => TextEmphasisShapeKeyword::Circle, - structs::NS_STYLE_TEXT_EMPHASIS_STYLE_DOUBLE_CIRCLE => TextEmphasisShapeKeyword::DoubleCircle, - structs::NS_STYLE_TEXT_EMPHASIS_STYLE_TRIANGLE => TextEmphasisShapeKeyword::Triangle, - structs::NS_STYLE_TEXT_EMPHASIS_STYLE_SESAME => TextEmphasisShapeKeyword::Sesame, - _ => panic!("Unexpected value in style struct for text-emphasis-style property") - }; - - TextEmphasisStyle::Keyword(TextEmphasisKeywordValue { fill, shape }) - } - ${impl_non_negative_length('_webkit_text_stroke_width', 'mWebkitTextStrokeWidth')} diff --git a/components/style/properties/longhands/border.mako.rs b/components/style/properties/longhands/border.mako.rs index 6ac01034bedb..4098a94208fd 100644 --- a/components/style/properties/longhands/border.mako.rs +++ b/components/style/properties/longhands/border.mako.rs @@ -58,7 +58,6 @@ animation_value_type="NonNegativeLength", logical=is_logical, logical_group="border-width", - flags="GETCS_NEEDS_LAYOUT_FLUSH", allow_quirks="No" if is_logical else "Yes", servo_restyle_damage="reflow rebuild_and_reflow_inline" )} diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index 40075a650843..4dcc43aec239 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -339,8 +339,7 @@ ${helpers.predefined_type( servo_2020_pref="layout.2020.unimplemented", extra_prefixes=transform_extra_prefixes, animation_value_type="ComputedValue", - flags="CREATES_STACKING_CONTEXT FIXPOS_CB \ - GETCS_NEEDS_LAYOUT_FLUSH CAN_ANIMATE_ON_COMPOSITOR", + flags="CREATES_STACKING_CONTEXT FIXPOS_CB CAN_ANIMATE_ON_COMPOSITOR", spec="https://drafts.csswg.org/css-transforms/#propdef-transform", servo_restyle_damage="reflow_out_of_flow", )} @@ -421,6 +420,19 @@ ${helpers.predefined_type( servo_restyle_damage="reflow_out_of_flow" )} +// Motion Path Module Level 1 +${helpers.predefined_type( + "offset-anchor", + "PositionOrAuto", + "computed::PositionOrAuto::auto()", + engines="gecko", + animation_value_type="ComputedValue", + gecko_pref="layout.css.motion-path.enabled", + spec="https://drafts.fxtf.org/motion-1/#offset-anchor-property", + servo_restyle_damage="reflow_out_of_flow", + boxed=True +)} + // CSSOM View Module // https://www.w3.org/TR/cssom-view-1/ ${helpers.single_keyword( @@ -539,7 +551,6 @@ ${helpers.predefined_type( boxed=True, extra_prefixes=transform_extra_prefixes, spec="https://drafts.csswg.org/css-transforms-2/#perspective-origin-property", - flags="GETCS_NEEDS_LAYOUT_FLUSH", animation_value_type="ComputedValue", servo_restyle_damage="reflow_out_of_flow" )} @@ -587,7 +598,6 @@ ${helpers.predefined_type( extra_prefixes=transform_extra_prefixes, gecko_ffi_name="mTransformOrigin", boxed=True, - flags="GETCS_NEEDS_LAYOUT_FLUSH", spec="https://drafts.csswg.org/css-transforms/#transform-origin-property", servo_restyle_damage="reflow_out_of_flow", )} diff --git a/components/style/properties/longhands/inherited_text.mako.rs b/components/style/properties/longhands/inherited_text.mako.rs index f45369c27c77..18f5c466d1a0 100644 --- a/components/style/properties/longhands/inherited_text.mako.rs +++ b/components/style/properties/longhands/inherited_text.mako.rs @@ -23,7 +23,6 @@ ${helpers.predefined_type( engines="gecko servo-2013 servo-2020", servo_2020_pref="layout.2020.unimplemented", animation_value_type="LineHeight", - flags="GETCS_NEEDS_LAYOUT_FLUSH", spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height", servo_restyle_damage="reflow" )} @@ -250,7 +249,6 @@ ${helpers.predefined_type( None, engines="gecko", initial_specified_value="SpecifiedValue::None", - boxed=True, animation_value_type="discrete", spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-style", )} @@ -384,8 +382,8 @@ ${helpers.single_keyword( // text underline offset ${helpers.predefined_type( "text-underline-offset", - "LengthOrAuto", - "computed::LengthOrAuto::auto()", + "TextDecorationLength", + "generics::text::GenericTextDecorationLength::Auto", engines="gecko", animation_value_type="ComputedValue", gecko_pref="layout.css.text-underline-offset.enabled", diff --git a/components/style/properties/longhands/margin.mako.rs b/components/style/properties/longhands/margin.mako.rs index 820634be9952..9ec1e97504c5 100644 --- a/components/style/properties/longhands/margin.mako.rs +++ b/components/style/properties/longhands/margin.mako.rs @@ -24,7 +24,6 @@ logical=side[1], logical_group="margin", spec=spec, - flags="GETCS_NEEDS_LAYOUT_FLUSH", allowed_in_page_rule=True, servo_restyle_damage="reflow" )} diff --git a/components/style/properties/longhands/padding.mako.rs b/components/style/properties/longhands/padding.mako.rs index faa3fb2867c5..a91f1238979b 100644 --- a/components/style/properties/longhands/padding.mako.rs +++ b/components/style/properties/longhands/padding.mako.rs @@ -23,7 +23,6 @@ logical=side[1], logical_group="padding", spec=spec, - flags="GETCS_NEEDS_LAYOUT_FLUSH", allow_quirks="No" if side[1] else "Yes", servo_restyle_damage="reflow rebuild_and_reflow_inline" )} diff --git a/components/style/properties/longhands/position.mako.rs b/components/style/properties/longhands/position.mako.rs index 9e67dfb2d806..a63f7637db4c 100644 --- a/components/style/properties/longhands/position.mako.rs +++ b/components/style/properties/longhands/position.mako.rs @@ -17,7 +17,6 @@ engines="gecko servo-2013 servo-2020", servo_2020_pref="layout.2020.unimplemented", spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side, - flags="GETCS_NEEDS_LAYOUT_FLUSH", animation_value_type="ComputedValue", allow_quirks="Yes", servo_restyle_damage="reflow_out_of_flow", @@ -33,7 +32,6 @@ engines="gecko servo-2013 servo-2020", servo_2020_pref="layout.2020.unimplemented", spec="https://drafts.csswg.org/css-logical-props/#propdef-inset-%s" % side, - flags="GETCS_NEEDS_LAYOUT_FLUSH", alias="offset-%s:layout.css.offset-logical-properties.enabled" % side, animation_value_type="ComputedValue", logical=True, @@ -285,7 +283,6 @@ ${helpers.predefined_type( allow_quirks="No" if logical else "Yes", spec=spec % size, animation_value_type="Size", - flags="GETCS_NEEDS_LAYOUT_FLUSH", servo_restyle_damage="reflow", )} // min-width, min-height, min-block-size, min-inline-size @@ -360,16 +357,13 @@ ${helpers.predefined_type( )} % endfor - // NOTE: According to the spec, this should handle multiple values of ``, - // but gecko supports only a single value ${helpers.predefined_type( "grid-auto-%ss" % kind, - "TrackSize", + "ImplicitGridTracks", "Default::default()", engines="gecko", animation_value_type="discrete", spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind, - boxed=True, )} ${helpers.predefined_type( @@ -378,8 +372,6 @@ ${helpers.predefined_type( "specified::GenericGridTemplateComponent::None", engines="gecko", spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-%ss" % kind, - boxed=True, - flags="GETCS_NEEDS_LAYOUT_FLUSH", animation_value_type="ComputedValue", )} diff --git a/components/style/properties/longhands/text.mako.rs b/components/style/properties/longhands/text.mako.rs index a592e2f12908..b77e17dd6b75 100644 --- a/components/style/properties/longhands/text.mako.rs +++ b/components/style/properties/longhands/text.mako.rs @@ -71,9 +71,10 @@ ${helpers.predefined_type( ${helpers.predefined_type( "text-decoration-thickness", - "LengthOrAuto", - "computed::LengthOrAuto::auto()", + "TextDecorationLength", + "generics::text::GenericTextDecorationLength::Auto", engines="gecko", + initial_specified_value="generics::text::GenericTextDecorationLength::Auto", animation_value_type="ComputedValue", gecko_pref="layout.css.text-decoration-thickness.enabled", spec="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property" diff --git a/components/style/properties/longhands/ui.mako.rs b/components/style/properties/longhands/ui.mako.rs index d59be17a27a9..647028559677 100644 --- a/components/style/properties/longhands/ui.mako.rs +++ b/components/style/properties/longhands/ui.mako.rs @@ -80,7 +80,6 @@ ${helpers.predefined_type( "Transform", "generics::transform::Transform::none()", engines="gecko", - flags="GETCS_NEEDS_LAYOUT_FLUSH", animation_value_type="ComputedValue", spec="None (Nonstandard internal property)", enabled_in="chrome", @@ -94,7 +93,6 @@ ${helpers.predefined_type( animation_value_type="ComputedValue", gecko_ffi_name="mWindowTransformOrigin", boxed=True, - flags="GETCS_NEEDS_LAYOUT_FLUSH", spec="None (Nonstandard internal property)", enabled_in="chrome", )} diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index c16de38f2042..72ae381f5d9f 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -981,13 +981,10 @@ bitflags! { const APPLIES_TO_CUE = 1 << 6; /// This longhand property applies to ::marker. const APPLIES_TO_MARKER = 1 << 7; - /// This property's getComputedStyle implementation requires layout - /// to be flushed. - const GETCS_NEEDS_LAYOUT_FLUSH = 1 << 8; /// This property is a legacy shorthand. /// /// https://drafts.csswg.org/css-cascade/#legacy-shorthand - const IS_LEGACY_SHORTHAND = 1 << 9; + const IS_LEGACY_SHORTHAND = 1 << 8; /* The following flags are currently not used in Rust code, they * only need to be listed in corresponding properties so that diff --git a/components/style/properties/shorthands/position.mako.rs b/components/style/properties/shorthands/position.mako.rs index 8e61f0f6ecdd..81a54dbfa572 100644 --- a/components/style/properties/shorthands/position.mako.rs +++ b/components/style/properties/shorthands/position.mako.rs @@ -268,7 +268,7 @@ > use crate::parser::Parse; use servo_arc::Arc; - use crate::values::generics::grid::{TrackSize, TrackList, TrackListType}; + use crate::values::generics::grid::{TrackSize, TrackList}; use crate::values::generics::grid::{TrackListValue, concat_serialize_idents}; use crate::values::specified::{GridTemplateComponent, GenericGridTemplateComponent}; use crate::values::specified::grid::parse_line_names; @@ -300,26 +300,28 @@ } % endfor - let first_line_names = input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice()); + let first_line_names = input.try(parse_line_names).unwrap_or_default(); if let Ok(mut string) = input.try(|i| i.expect_string().map(|s| s.as_ref().to_owned().into())) { let mut strings = vec![]; let mut values = vec![]; let mut line_names = vec![]; - let mut names = first_line_names.into_vec(); + let mut names = first_line_names; loop { - line_names.push(names.into_boxed_slice()); + line_names.push(names); strings.push(string); let size = input.try(|i| TrackSize::parse(context, i)).unwrap_or_default(); values.push(TrackListValue::TrackSize(size)); - names = input.try(parse_line_names).unwrap_or(vec![].into_boxed_slice()).into_vec(); + names = input.try(parse_line_names).unwrap_or_default(); if let Ok(v) = input.try(parse_line_names) { - names.extend(v.into_vec()); + let mut names_vec = names.into_vec(); + names_vec.extend(v.into_iter()); + names = names_vec.into(); } string = match input.try(|i| i.expect_string().map(|s| s.as_ref().to_owned().into())) { Ok(s) => s, _ => { // only the named area determines whether we should bail out - line_names.push(names.into_boxed_slice()); + line_names.push(names.into()); break }, }; @@ -327,22 +329,21 @@ if line_names.len() == values.len() { // should be one longer than track sizes - line_names.push(vec![].into_boxed_slice()); + line_names.push(Default::default()); } let template_areas = TemplateAreas::from_vec(strings) .map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))?; let template_rows = TrackList { - list_type: TrackListType::Normal, - values, - line_names: line_names.into_boxed_slice(), - auto_repeat: None, + values: values.into(), + line_names: line_names.into(), + auto_repeat_index: std::usize::MAX, }; let template_cols = if input.try(|i| i.expect_delim('/')).is_ok() { let value = GridTemplateComponent::parse_without_none(context, input)?; if let GenericGridTemplateComponent::TrackList(ref list) = value { - if list.list_type != TrackListType::Explicit { + if !list.is_explicit() { return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) } } @@ -352,8 +353,11 @@ GenericGridTemplateComponent::None }; - Ok((GenericGridTemplateComponent::TrackList(template_rows), - template_cols, GridTemplateAreas::Areas(TemplateAreasArc(Arc::new(template_areas))))) + Ok(( + GenericGridTemplateComponent::TrackList(Box::new(template_rows)), + template_cols, + GridTemplateAreas::Areas(TemplateAreasArc(Arc::new(template_areas))) + )) } else { let mut template_rows = GridTemplateComponent::parse(context, input)?; if let GenericGridTemplateComponent::TrackList(ref mut list) = template_rows { @@ -407,13 +411,10 @@ let track_list = match *template_rows { GenericGridTemplateComponent::TrackList(ref list) => { - // We should fail if there is a `repeat` function. `grid` and - // `grid-template` shorthands doesn't accept that. Only longhand accepts. - if list.auto_repeat.is_some() || - list.values.iter().any(|v| match *v { - TrackListValue::TrackRepeat(_) => true, - _ => false, - }) { + // We should fail if there is a `repeat` function. + // `grid` and `grid-template` shorthands doesn't accept + // that. Only longhand accepts. + if !list.is_explicit() { return Ok(()); } list @@ -429,11 +430,7 @@ // We should fail if there is a `repeat` function. `grid` and // `grid-template` shorthands doesn't accept that. Only longhand accepts that. GenericGridTemplateComponent::TrackList(ref list) => { - if list.auto_repeat.is_some() || - list.values.iter().any(|v| match *v { - TrackListValue::TrackRepeat(_) => true, - _ => false, - }) { + if !list.is_explicit() { return Ok(()); } }, @@ -498,8 +495,8 @@ > use crate::parser::Parse; use crate::properties::longhands::{grid_auto_columns, grid_auto_rows, grid_auto_flow}; - use crate::values::generics::grid::{GridTemplateComponent, TrackListType}; - use crate::values::specified::{GenericGridTemplateComponent, TrackSize}; + use crate::values::generics::grid::GridTemplateComponent; + use crate::values::specified::{GenericGridTemplateComponent, ImplicitGridTracks}; use crate::values::specified::position::{AutoFlow, GridAutoFlow, GridTemplateAreas}; pub fn parse_value<'i, 't>( @@ -509,8 +506,8 @@ let mut temp_rows = GridTemplateComponent::None; let mut temp_cols = GridTemplateComponent::None; let mut temp_areas = GridTemplateAreas::None; - let mut auto_rows = TrackSize::default(); - let mut auto_cols = TrackSize::default(); + let mut auto_rows = ImplicitGridTracks::default(); + let mut auto_cols = ImplicitGridTracks::default(); let mut flow = grid_auto_flow::get_initial_value(); fn parse_auto_flow<'i, 't>( @@ -571,8 +568,8 @@ /// Returns true if other sub properties except template-{rows,columns} are initial. fn is_grid_template(&self) -> bool { *self.grid_template_areas == GridTemplateAreas::None && - *self.grid_auto_rows == TrackSize::default() && - *self.grid_auto_columns == TrackSize::default() && + self.grid_auto_rows.is_initial() && + self.grid_auto_columns.is_initial() && *self.grid_auto_flow == grid_auto_flow::get_initial_value() } } @@ -590,14 +587,14 @@ if self.grid_auto_flow.autoflow == AutoFlow::Column { // It should fail to serialize if other branch of the if condition's values are set. - if *self.grid_auto_rows != TrackSize::default() || + if !self.grid_auto_rows.is_initial() || *self.grid_template_columns != GridTemplateComponent::None { return Ok(()); } // It should fail to serialize if template-rows value is not Explicit. if let GenericGridTemplateComponent::TrackList(ref list) = *self.grid_template_rows { - if list.list_type != TrackListType::Explicit { + if !list.is_explicit() { return Ok(()); } } @@ -608,20 +605,20 @@ dest.write_str(" dense")?; } - if !self.grid_auto_columns.is_default() { + if !self.grid_auto_columns.is_initial() { dest.write_str(" ")?; self.grid_auto_columns.to_css(dest)?; } } else { // It should fail to serialize if other branch of the if condition's values are set. - if *self.grid_auto_columns != TrackSize::default() || + if !self.grid_auto_columns.is_initial() || *self.grid_template_rows != GridTemplateComponent::None { return Ok(()); } // It should fail to serialize if template-column value is not Explicit. if let GenericGridTemplateComponent::TrackList(ref list) = *self.grid_template_columns { - if list.list_type != TrackListType::Explicit { + if !list.is_explicit() { return Ok(()); } } @@ -631,7 +628,7 @@ dest.write_str(" dense")?; } - if !self.grid_auto_rows.is_default() { + if !self.grid_auto_rows.is_initial() { dest.write_str(" ")?; self.grid_auto_rows.to_css(dest)?; } diff --git a/components/style/properties/shorthands/text.mako.rs b/components/style/properties/shorthands/text.mako.rs index 905512b08df8..33b4a074892c 100644 --- a/components/style/properties/shorthands/text.mako.rs +++ b/components/style/properties/shorthands/text.mako.rs @@ -8,12 +8,13 @@ engines="gecko servo-2013" flags="SHORTHAND_IN_GETCS" sub_properties="text-decoration-line - ${' text-decoration-style text-decoration-color' if engine == 'gecko' else ''}" + ${' text-decoration-style text-decoration-color text-decoration-thickness' if engine == 'gecko' else ''}" spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration"> % if engine == "gecko": use crate::values::specified; - use crate::properties::longhands::{text_decoration_style, text_decoration_color}; + use crate::properties::longhands::{text_decoration_style, text_decoration_color, text_decoration_thickness}; + use crate::properties::{PropertyId, LonghandId}; % endif use crate::properties::longhands::text_decoration_line; @@ -22,7 +23,10 @@ input: &mut Parser<'i, 't>, ) -> Result> { % if engine == "gecko": - let (mut line, mut style, mut color, mut any) = (None, None, None, false); + let text_decoration_thickness_enabled = + PropertyId::Longhand(LonghandId::TextDecorationThickness).enabled_for_all_content(); + + let (mut line, mut style, mut color, mut thickness, mut any) = (None, None, None, None, false); % else: let (mut line, mut any) = (None, false); % endif @@ -45,6 +49,9 @@ % if engine == "gecko": parse_component!(style, text_decoration_style); parse_component!(color, text_decoration_color); + if text_decoration_thickness_enabled { + parse_component!(thickness, text_decoration_thickness); + } % endif break; @@ -60,6 +67,7 @@ % if engine == "gecko": text_decoration_style: unwrap_or_initial!(text_decoration_style, style), text_decoration_color: unwrap_or_initial!(text_decoration_color, color), + text_decoration_thickness: unwrap_or_initial!(text_decoration_thickness, thickness), % endif }) } @@ -78,6 +86,13 @@ dest.write_str(" ")?; self.text_decoration_color.to_css(dest)?; } + + if let Some(text_decoration_thickness) = self.text_decoration_thickness { + if !text_decoration_thickness.is_auto() { + dest.write_str(" ")?; + self.text_decoration_thickness.to_css(dest)?; + } + } % endif Ok(()) diff --git a/components/style/style_adjuster.rs b/components/style/style_adjuster.rs index 38b908a16c63..041d2f76cafa 100644 --- a/components/style/style_adjuster.rs +++ b/components/style/style_adjuster.rs @@ -12,6 +12,7 @@ use crate::properties::longhands::float::computed_value::T as Float; use crate::properties::longhands::overflow_x::computed_value::T as Overflow; use crate::properties::longhands::position::computed_value::T as Position; use crate::properties::{self, ComputedValues, StyleBuilder}; +use crate::values::specified::box_::DisplayInside; use app_units::Au; /// A struct that implements all the adjustment methods. @@ -175,7 +176,9 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { /// Apply the blockification rules based on the table in CSS 2.2 section 9.7. /// /// A ::marker pseudo-element with 'list-style-position:outside' needs to - /// have its 'display' blockified. + /// have its 'display' blockified, unless the ::marker is for an inline + /// list-item (for which 'list-style-position:outside' behaves as 'inside'). + /// https://drafts.csswg.org/css-lists-3/#list-style-position-property fn blockify_if_necessary(&mut self, layout_parent_style: &ComputedValues, element: Option) where E: TElement, @@ -194,10 +197,8 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { let is_root = self.style.pseudo.is_none() && element.map_or(false, |e| e.is_root()); blockify_if!(is_root); if !self.skip_item_display_fixup(element) { - blockify_if!(layout_parent_style - .get_box() - .clone_display() - .is_item_container()); + let parent_display = layout_parent_style.get_box().clone_display(); + blockify_if!(parent_display.is_item_container()); } let is_item_or_root = blockify; @@ -207,7 +208,8 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { blockify_if!( self.style.pseudo.map_or(false, |p| p.is_marker()) && self.style.get_parent_list().clone_list_style_position() == - ListStylePosition::Outside + ListStylePosition::Outside && + layout_parent_style.get_box().clone_display().inside() != DisplayInside::Inline ); if !blockify { diff --git a/components/style/stylesheets/document_rule.rs b/components/style/stylesheets/document_rule.rs index 62e814ac48bd..942d60a7d178 100644 --- a/components/style/stylesheets/document_rule.rs +++ b/components/style/stylesheets/document_rule.rs @@ -253,20 +253,18 @@ impl DocumentCondition { #[cfg(feature = "gecko")] fn allowed_in(&self, context: &ParserContext) -> bool { - use crate::gecko_bindings::structs; use crate::stylesheets::Origin; + use static_prefs::pref; if context.stylesheet_origin != Origin::Author { return true; } - if unsafe { structs::StaticPrefs::sVarCache_layout_css_moz_document_content_enabled } { + if pref!("layout.css.moz-document.content.enabled") { return true; } - if !unsafe { - structs::StaticPrefs::sVarCache_layout_css_moz_document_url_prefix_hack_enabled - } { + if !pref!("layout.css.moz-document.url-prefix-hack.enabled") { return false; } diff --git a/components/style/stylesheets/supports_rule.rs b/components/style/stylesheets/supports_rule.rs index 4b709974c7dc..9ef3558bd1c2 100644 --- a/components/style/stylesheets/supports_rule.rs +++ b/components/style/stylesheets/supports_rule.rs @@ -323,9 +323,7 @@ impl RawSelector { pub fn eval(&self, context: &ParserContext, namespaces: &Namespaces) -> bool { #[cfg(feature = "gecko")] { - if unsafe { - !crate::gecko_bindings::structs::StaticPrefs::sVarCache_layout_css_supports_selector_enabled - } { + if !static_prefs::pref!("layout.css.supports-selector.enabled") { return false; } } diff --git a/components/style/values/animated/grid.rs b/components/style/values/animated/grid.rs index d1f6be1a32b2..7b9417a08c6f 100644 --- a/components/style/values/animated/grid.rs +++ b/components/style/values/animated/grid.rs @@ -101,7 +101,7 @@ impl Animate for generics::TrackRepeat { Ok(generics::TrackRepeat { count, line_names, - track_sizes, + track_sizes: track_sizes.into(), }) } } @@ -117,20 +117,19 @@ impl Animate for TrackList { return Err(()); } - if self.list_type != other.list_type { + if self.is_explicit() != other.is_explicit() { return Err(()); } - // For now, repeat(auto-fill/auto-fit, ...) is not animatable. TrackRepeat will - // return Err(()) if we use keywords. Therefore, we can early return here to avoid - // traversing |values| in . This may be updated in the future. + // For now, repeat(auto-fill/auto-fit, ...) is not animatable. + // TrackRepeat will return Err(()) if we use keywords. Therefore, we can + // early return here to avoid traversing |values| in . + // This may be updated in the future. // https://github.com/w3c/csswg-drafts/issues/3503 - if let generics::TrackListType::Auto(_) = self.list_type { + if self.has_auto_repeat() || other.has_auto_repeat() { return Err(()); } - let list_type = self.list_type; - let auto_repeat = self.auto_repeat.animate(&other.auto_repeat, procedure)?; let values = self .values .iter() @@ -142,10 +141,9 @@ impl Animate for TrackList { let line_names = discrete(&self.line_names, &other.line_names, procedure)?; Ok(TrackList { - list_type, - values, + values: values.into(), line_names, - auto_repeat, + auto_repeat_index: self.auto_repeat_index, }) } } diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 7cfe0de6d8d4..bd78d376b35f 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -7,6 +7,7 @@ use self::transform::DirectionVector; use super::animated::ToAnimatedValue; use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; +use super::generics::grid::ImplicitGridTracks as GenericImplicitGridTracks; use super::generics::grid::{GenericGridLine, GenericTrackBreadth}; use super::generics::grid::{GenericTrackSize, TrackList as GenericTrackList}; use super::generics::transform::IsParallelTo; @@ -68,17 +69,17 @@ pub use self::list::Quotes; pub use self::motion::{OffsetPath, OffsetRotate}; pub use self::outline::OutlineStyle; pub use self::percentage::{NonNegativePercentage, Percentage}; -pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex}; +pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, PositionOrAuto, ZIndex}; pub use self::rect::NonNegativeLengthOrNumberRect; pub use self::resolution::Resolution; pub use self::svg::MozContextProperties; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::table::XSpan; -pub use self::text::TextDecorationSkipInk; pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight}; pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing}; pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle}; +pub use self::text::{TextDecorationLength, TextDecorationSkipInk}; pub use self::time::Time; pub use self::transform::{Rotate, Scale, Transform, TransformOperation}; pub use self::transform::{TransformOrigin, TransformStyle, Translate}; @@ -467,6 +468,7 @@ trivial_to_computed_value!(i32); trivial_to_computed_value!(u8); trivial_to_computed_value!(u16); trivial_to_computed_value!(u32); +trivial_to_computed_value!(usize); trivial_to_computed_value!(Atom); #[cfg(feature = "servo")] trivial_to_computed_value!(Prefix); @@ -695,6 +697,9 @@ pub type TrackBreadth = GenericTrackBreadth; /// The computed value of a grid `` pub type TrackSize = GenericTrackSize; +/// The computed value of a grid `+` +pub type ImplicitGridTracks = GenericImplicitGridTracks; + /// The computed value of a grid `` /// (could also be `` or ``) pub type TrackList = GenericTrackList; diff --git a/components/style/values/computed/position.rs b/components/style/values/computed/position.rs index f0f8fe198a64..7b22c37f73f2 100644 --- a/components/style/values/computed/position.rs +++ b/components/style/values/computed/position.rs @@ -9,6 +9,7 @@ use crate::values::computed::{Integer, LengthPercentage, Percentage}; use crate::values::generics::position::Position as GenericPosition; +use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto; use crate::values::generics::position::ZIndex as GenericZIndex; pub use crate::values::specified::position::{GridAutoFlow, GridTemplateAreas}; use crate::Zero; @@ -18,6 +19,9 @@ use style_traits::{CssWriter, ToCss}; /// The computed value of a CSS `` pub type Position = GenericPosition; +/// The computed value of an `auto | ` +pub type PositionOrAuto = GenericPositionOrAuto; + /// The computed value of a CSS horizontal position. pub type HorizontalPosition = LengthPercentage; diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs index 7201c1aff611..bdb2ac507bc7 100644 --- a/components/style/values/computed/text.rs +++ b/components/style/values/computed/text.rs @@ -10,7 +10,7 @@ use crate::values::computed::length::{Length, LengthPercentage}; use crate::values::computed::{Context, NonNegativeLength, NonNegativeNumber, ToComputedValue}; use crate::values::generics::text::InitialLetter as GenericInitialLetter; use crate::values::generics::text::LineHeight as GenericLineHeight; -use crate::values::generics::text::Spacing; +use crate::values::generics::text::{GenericTextDecorationLength, Spacing}; use crate::values::specified::text::{self as specified, TextOverflowSide}; use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword}; use crate::values::{CSSFloat, CSSInteger}; @@ -26,6 +26,9 @@ pub use crate::values::specified::{TextDecorationSkipInk, TextTransform}; /// A computed value for the `initial-letter` property. pub type InitialLetter = GenericInitialLetter; +/// Implements type for `text-underline-offset` and `text-decoration-thickness` properties +pub type TextDecorationLength = GenericTextDecorationLength; + /// A computed value for the `letter-spacing` property. #[repr(transparent)] #[derive( @@ -194,22 +197,21 @@ impl TextDecorationsInEffect { } } -/// computed value for the text-emphasis-style property +/// Computed value for the text-emphasis-style property +/// +/// cbindgen:derive-tagged-enum-copy-constructor=true #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)] +#[allow(missing_docs)] +#[repr(C, u8)] pub enum TextEmphasisStyle { - /// Keyword value for the text-emphasis-style property (`filled` `open`) - Keyword(TextEmphasisKeywordValue), + /// [ || ] + Keyword { + #[css(skip_if = "TextEmphasisFillMode::is_filled")] + fill: TextEmphasisFillMode, + shape: TextEmphasisShapeKeyword, + }, /// `none` None, - /// String (will be used only first grapheme cluster) for the text-emphasis-style property - String(String), -} - -/// Keyword value for the text-emphasis-style property -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)] -pub struct TextEmphasisKeywordValue { - /// fill for the text-emphasis-style property - pub fill: TextEmphasisFillMode, - /// shape for the text-emphasis-style property - pub shape: TextEmphasisShapeKeyword, + /// `` (of which only the first grapheme cluster will be used). + String(crate::OwnedStr), } diff --git a/components/style/values/generics/easing.rs b/components/style/values/generics/easing.rs index aab2ef547bac..b234b6a54e00 100644 --- a/components/style/values/generics/easing.rs +++ b/components/style/values/generics/easing.rs @@ -69,8 +69,7 @@ pub enum TimingKeyword { #[cfg(feature = "gecko")] fn step_position_jump_enabled(_context: &ParserContext) -> bool { - use crate::gecko_bindings::structs; - unsafe { structs::StaticPrefs::sVarCache_layout_css_step_position_jump_enabled } + static_prefs::pref!("layout.css.step-position-jump.enabled") } #[cfg(feature = "servo")] diff --git a/components/style/values/generics/font.rs b/components/style/values/generics/font.rs index 59907ff79201..eb8eac191f00 100644 --- a/components/style/values/generics/font.rs +++ b/components/style/values/generics/font.rs @@ -253,9 +253,7 @@ pub enum KeywordSize { XLarge, #[css(keyword = "xx-large")] XXLarge, - // This is not a real font keyword and will not parse - // HTML font-size 7 corresponds to this value - #[css(skip)] + #[css(keyword = "xxx-large")] XXXLarge, } diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs index 7de109141fe8..b9e173ea50f3 100644 --- a/components/style/values/generics/grid.rs +++ b/components/style/values/generics/grid.rs @@ -12,7 +12,7 @@ use crate::values::{CSSFloat, CustomIdent}; use crate::{Atom, Zero}; use cssparser::Parser; use std::fmt::{self, Write}; -use std::{cmp, mem, usize}; +use std::{cmp, usize}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; /// These are the limits that we choose to clamp grid line numbers to. @@ -290,16 +290,17 @@ impl TrackSize { } } -impl Default for TrackSize { - fn default() -> Self { - TrackSize::Breadth(TrackBreadth::Auto) +impl TrackSize { + /// Return true if it is `auto`. + #[inline] + pub fn is_auto(&self) -> bool { + *self == TrackSize::Breadth(TrackBreadth::Auto) } } -impl TrackSize { - /// Returns true if current TrackSize is same as default. - pub fn is_default(&self) -> bool { - *self == TrackSize::default() +impl Default for TrackSize { + fn default() -> Self { + TrackSize::Breadth(TrackBreadth::Auto) } } @@ -334,6 +335,39 @@ impl ToCss for TrackSize { } } +/// A `+`. +/// We use the empty slice as `auto`, and always parse `auto` as an empty slice. +/// This means it's impossible to have a slice containing only one auto item. +#[derive( + Clone, + Debug, + Default, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[repr(transparent)] +pub struct GenericImplicitGridTracks( + #[css(if_empty = "auto", iterable)] pub crate::OwnedSlice, +); + +pub use self::GenericImplicitGridTracks as ImplicitGridTracks; + +impl ImplicitGridTracks { + /// Returns true if current value is same as its initial value (i.e. auto). + pub fn is_initial(&self) -> bool { + debug_assert_ne!( + *self, + ImplicitGridTracks(crate::OwnedSlice::from(vec![Default::default()])) + ); + self.0.is_empty() + } +} + /// Helper function for serializing identifiers with a prefix and suffix, used /// for serializing (in grid). pub fn concat_serialize_idents( @@ -366,6 +400,7 @@ where #[derive( Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, )] +#[repr(C, u8)] pub enum RepeatCount { /// A positive integer. This is allowed only for `` and `` Number(Integer), @@ -380,18 +415,15 @@ impl Parse for RepeatCount { context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { - // Maximum number of repeat is 10000. The greater numbers should be clamped. - const MAX_LINE: i32 = 10000; if let Ok(mut i) = input.try(|i| specified::Integer::parse_positive(context, i)) { - if i.value() > MAX_LINE { - i = specified::Integer::new(MAX_LINE); - } - Ok(RepeatCount::Number(i)) - } else { - try_match_ident_ignore_ascii_case! { input, - "auto-fill" => Ok(RepeatCount::AutoFill), - "auto-fit" => Ok(RepeatCount::AutoFit), + if i.value() > MAX_GRID_LINE { + i = specified::Integer::new(MAX_GRID_LINE); } + return Ok(RepeatCount::Number(i)); + } + try_match_ident_ignore_ascii_case! { input, + "auto-fill" => Ok(RepeatCount::AutoFill), + "auto-fit" => Ok(RepeatCount::AutoFit), } } } @@ -411,7 +443,8 @@ impl Parse for RepeatCount { ToShmem, )] #[css(function = "repeat")] -pub struct TrackRepeat { +#[repr(C)] +pub struct GenericTrackRepeat { /// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`) pub count: RepeatCount, /// `` accompanying `` values. @@ -419,11 +452,13 @@ pub struct TrackRepeat { /// If there's no ``, then it's represented by an empty vector. /// For N `` values, there will be N+1 ``, and so this vector's /// length is always one value more than that of the ``. - pub line_names: Box<[Box<[CustomIdent]>]>, + pub line_names: crate::OwnedSlice>, /// `` values. - pub track_sizes: Vec>, + pub track_sizes: crate::OwnedSlice>, } +pub use self::GenericTrackRepeat as TrackRepeat; + impl ToCss for TrackRepeat { fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where @@ -457,46 +492,10 @@ impl ToCss for TrackRepeat { Ok(()) } } -impl TrackRepeat { - /// If the repeat count is numeric, then expand the values and merge accordingly. - pub fn expand(&self) -> Self { - if let RepeatCount::Number(num) = self.count { - let mut line_names = vec![]; - let mut track_sizes = vec![]; - let mut prev_names = vec![]; - - for _ in 0..num.value() { - let mut names_iter = self.line_names.iter(); - for (size, names) in self.track_sizes.iter().zip(&mut names_iter) { - prev_names.extend_from_slice(&names); - let vec = mem::replace(&mut prev_names, vec![]); - line_names.push(vec.into_boxed_slice()); - track_sizes.push(size.clone()); - } - - if let Some(names) = names_iter.next() { - prev_names.extend_from_slice(&names); - } - } - - line_names.push(prev_names.into_boxed_slice()); - TrackRepeat { - count: self.count, - track_sizes: track_sizes, - line_names: line_names.into_boxed_slice(), - } - } else { - // if it's auto-fit/auto-fill, then it's left to the layout. - TrackRepeat { - count: self.count, - track_sizes: self.track_sizes.clone(), - line_names: self.line_names.clone(), - } - } - } -} /// Track list values. Can be or +/// +/// cbindgen:derive-tagged-enum-copy-constructor=true #[derive( Animate, Clone, @@ -509,56 +508,63 @@ impl TrackRepeat { ToResolvedValue, ToShmem, )] -pub enum TrackListValue { +#[repr(C, u8)] +pub enum GenericTrackListValue { /// A value. - TrackSize(#[animation(field_bound)] TrackSize), + TrackSize(#[animation(field_bound)] GenericTrackSize), /// A value. - TrackRepeat(#[animation(field_bound)] TrackRepeat), + TrackRepeat(#[animation(field_bound)] GenericTrackRepeat), } -/// The type of a `` as determined during parsing. -/// -/// -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] -pub enum TrackListType { - /// [``](https://drafts.csswg.org/css-grid/#typedef-auto-track-list) - /// - /// If this type exists, then the value at the index in `line_names` field in `TrackList` - /// has the `?` list that comes before ``. If it's a specified value, - /// then the `repeat()` function (that follows the line names list) is also at the given index - /// in `values` field. On the contrary, if it's a computed value, then the `repeat()` function - /// is in the `auto_repeat` field. - Auto(u16), - /// [``](https://drafts.csswg.org/css-grid/#typedef-track-list) - Normal, - /// [``](https://drafts.csswg.org/css-grid/#typedef-explicit-track-list) - /// - /// Note that this is a subset of the normal ``, and so it could be used in place - /// of the latter. - Explicit, +pub use self::GenericTrackListValue as TrackListValue; + +impl TrackListValue { + fn is_repeat(&self) -> bool { + matches!(*self, TrackListValue::TrackRepeat(..)) + } } /// A grid `` type. /// /// -#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToResolvedValue, ToShmem)] -pub struct TrackList { - /// The type of this `` (auto, explicit or general). - /// - /// In order to avoid parsing the same value multiple times, this does a single traversal - /// and arrives at the type of value it has parsed (or bails out gracefully with an error). +#[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] +#[repr(C)] +pub struct GenericTrackList { + /// The index in `values` where our `` value is, if in bounds. #[css(skip)] - pub list_type: TrackListType, + pub auto_repeat_index: usize, /// A vector of ` | ` values. - pub values: Vec>, + pub values: crate::OwnedSlice>, /// `` accompanying ` | ` values. /// /// If there's no ``, then it's represented by an empty vector. /// For N values, there will be N+1 ``, and so this vector's /// length is always one value more than that of the ``. - pub line_names: Box<[Box<[CustomIdent]>]>, - /// `` value. There can only be one `` in a TrackList. - pub auto_repeat: Option>, + pub line_names: crate::OwnedSlice>, +} + +pub use self::GenericTrackList as TrackList; + +impl TrackList { + /// Whether this track list is an explicit track list (that is, doesn't have + /// any repeat values). + pub fn is_explicit(&self) -> bool { + !self.values.iter().any(|v| v.is_repeat()) + } + + /// Whether this track list has an `` value. + pub fn has_auto_repeat(&self) -> bool { + self.auto_repeat_index < self.values.len() + } } impl ToCss for TrackList { @@ -566,11 +572,6 @@ impl ToCss for TrackList { where W: Write, { - let auto_idx = match self.list_type { - TrackListType::Auto(i) => i as usize, - _ => usize::MAX, - }; - let mut values_iter = self.values.iter().peekable(); let mut line_names_iter = self.line_names.iter().peekable(); @@ -578,29 +579,20 @@ impl ToCss for TrackList { let names = line_names_iter.next().unwrap(); // This should exist! concat_serialize_idents("[", "]", names, " ", dest)?; - match self.auto_repeat { - Some(ref repeat) if idx == auto_idx => { + match values_iter.next() { + Some(value) => { if !names.is_empty() { dest.write_str(" ")?; } - repeat.to_css(dest)?; - }, - _ => match values_iter.next() { - Some(value) => { - if !names.is_empty() { - dest.write_str(" ")?; - } - - value.to_css(dest)?; - }, - None => break, + value.to_css(dest)?; }, + None => break, } if values_iter.peek().is_some() || line_names_iter.peek().map_or(false, |v| !v.is_empty()) || - (idx + 1 == auto_idx) + (idx + 1 == self.auto_repeat_index) { dest.write_str(" ")?; } @@ -613,7 +605,8 @@ impl ToCss for TrackList { /// The `` for subgrids. /// /// `subgrid [ | repeat( | auto-fill, +) ]+` -/// Old spec: https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-line-name-list +/// +/// https://drafts.csswg.org/css-grid-2/#typedef-line-name-list #[derive( Clone, Debug, @@ -625,11 +618,12 @@ impl ToCss for TrackList { ToResolvedValue, ToShmem, )] +#[repr(C)] pub struct LineNameList { /// The optional `` - pub names: Box<[Box<[CustomIdent]>]>, - /// Indicates the line name that requires `auto-fill` - pub fill_idx: Option, + pub names: crate::OwnedSlice>, + /// Indicates the line name that requires `auto-fill`, if in bounds. + pub fill_idx: usize, } impl Parse for LineNameList { @@ -652,13 +646,17 @@ impl Parse for LineNameList { while let Ok(names) = input.try(parse_line_names) { names_list.push(names); } - Ok((names_list, count)) }) }); if let Ok((mut names_list, count)) = repeat_parse_result { match count { + // FIXME(emilio): we probably shouldn't expand repeat() at + // parse time for subgrid. + // + // Also this doesn't have the merging semantics that + // non-subgrid has... But maybe that's ok? RepeatCount::Number(num) => line_names.extend( names_list .iter() @@ -676,7 +674,7 @@ impl Parse for LineNameList { let names = names_list.pop().unwrap(); line_names.push(names); - fill_idx = Some(line_names.len() as u32 - 1); + fill_idx = Some(line_names.len() - 1); }, _ => return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)), } @@ -687,9 +685,13 @@ impl Parse for LineNameList { } } + if line_names.len() > MAX_GRID_LINE as usize { + line_names.truncate(MAX_GRID_LINE as usize); + } + Ok(LineNameList { - names: line_names.into_boxed_slice(), - fill_idx: fill_idx, + names: line_names.into(), + fill_idx: fill_idx.unwrap_or(usize::MAX), }) } } @@ -700,7 +702,7 @@ impl ToCss for LineNameList { W: Write, { dest.write_str("subgrid")?; - let fill_idx = self.fill_idx.map(|v| v as usize).unwrap_or(usize::MAX); + let fill_idx = self.fill_idx; for (i, names) in self.names.iter().enumerate() { if i == fill_idx { dest.write_str(" repeat(auto-fill,")?; @@ -727,8 +729,8 @@ impl ToCss for LineNameList { } /// Variants for ` | ` -/// Subgrid deferred to Level 2 spec due to lack of implementation. -/// But it's implemented in gecko, so we have to as well. +/// +/// cbindgen:derive-tagged-enum-copy-constructor=true #[derive( Animate, Clone, @@ -741,7 +743,8 @@ impl ToCss for LineNameList { ToResolvedValue, ToShmem, )] -pub enum GridTemplateComponent { +#[repr(C, u8)] +pub enum GenericGridTemplateComponent { /// `none` value. None, /// The grid `` @@ -750,14 +753,16 @@ pub enum GridTemplateComponent { #[compute(field_bound)] #[resolve(field_bound)] #[shmem(field_bound)] - TrackList, + Box>, ), /// A `subgrid ?` /// TODO: Support animations for this after subgrid is addressed in [grid-2] spec. #[animation(error)] - Subgrid(LineNameList), + Subgrid(Box), } +pub use self::GenericGridTemplateComponent as GridTemplateComponent; + impl GridTemplateComponent { /// Returns length of the s pub fn track_list_len(&self) -> usize { diff --git a/components/style/values/generics/position.rs b/components/style/values/generics/position.rs index 7e43f439793d..2742dd879136 100644 --- a/components/style/values/generics/position.rs +++ b/components/style/values/generics/position.rs @@ -41,6 +41,43 @@ impl Position { } } +/// A generic type for representing an `Auto | `. +/// This is used by for now. +/// https://drafts.fxtf.org/motion-1/#offset-anchor-property +#[derive( + Animate, + Clone, + ComputeSquaredDistance, + Copy, + Debug, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToAnimatedZero, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[repr(C, u8)] +pub enum GenericPositionOrAuto { + /// The value. + Position(Pos), + /// The keyword `auto`. + Auto, +} + +pub use self::GenericPositionOrAuto as PositionOrAuto; + +impl PositionOrAuto { + /// Return `auto`. + #[inline] + pub fn auto() -> Self { + PositionOrAuto::Auto + } +} + /// A generic value for the `z-index` property. #[derive( Animate, diff --git a/components/style/values/generics/text.rs b/components/style/values/generics/text.rs index b55a9ad62dc5..fd434cc12738 100644 --- a/components/style/values/generics/text.rs +++ b/components/style/values/generics/text.rs @@ -72,11 +72,8 @@ impl Spacing { #[cfg(feature = "gecko")] fn line_height_moz_block_height_enabled(context: &ParserContext) -> bool { - use crate::gecko_bindings::structs; context.in_ua_sheet() || - unsafe { - structs::StaticPrefs::sVarCache_layout_css_line_height_moz_block_height_content_enabled - } + static_prefs::pref!("layout.css.line-height-moz-block-height.content.enabled") } /// A generic value for the `line-height` property. @@ -125,3 +122,33 @@ impl LineHeight { LineHeight::Normal } } + +/// Implements type for text-underline-offset and text-decoration-thickness +/// which take the grammar of auto | from-font | +/// +/// https://drafts.csswg.org/css-text-decor-4/ +#[repr(C, u8)] +#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] +#[derive( + Animate, + Clone, + Copy, + ComputeSquaredDistance, + ToAnimatedZero, + Debug, + Eq, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[allow(missing_docs)] +pub enum GenericTextDecorationLength { + Length(L), + Auto, + FromFont, +} diff --git a/components/style/values/resolved/mod.rs b/components/style/values/resolved/mod.rs index 379ea83ec6b1..e64178a1c957 100644 --- a/components/style/values/resolved/mod.rs +++ b/components/style/values/resolved/mod.rs @@ -65,6 +65,7 @@ trivial_to_resolved_value!(u8); trivial_to_resolved_value!(i8); trivial_to_resolved_value!(u16); trivial_to_resolved_value!(u32); +trivial_to_resolved_value!(usize); trivial_to_resolved_value!(String); trivial_to_resolved_value!(Box); trivial_to_resolved_value!(cssparser::RGBA); diff --git a/components/style/values/specified/basic_shape.rs b/components/style/values/specified/basic_shape.rs index 8dccf4594f00..3c32144e71cb 100644 --- a/components/style/values/specified/basic_shape.rs +++ b/components/style/values/specified/basic_shape.rs @@ -58,9 +58,7 @@ pub type Polygon = generic::GenericPolygon; #[cfg(feature = "gecko")] fn is_clip_path_path_enabled(context: &ParserContext) -> bool { - use crate::gecko_bindings::structs::mozilla; - context.chrome_rules_enabled() || - unsafe { mozilla::StaticPrefs::sVarCache_layout_css_clip_path_path_enabled } + context.chrome_rules_enabled() || static_prefs::pref!("layout.css.clip-path-path.enabled") } #[cfg(feature = "servo")] fn is_clip_path_path_enabled(_: &ParserContext) -> bool { diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index 0811a48be1a3..f481b940e052 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -16,6 +16,7 @@ use crate::values::specified::{AllowQuirks, Number}; use crate::values::{CustomIdent, KeyframesName}; use crate::Atom; use cssparser::Parser; +use num_traits::FromPrimitive; use selectors::parser::SelectorParseErrorKind; use std::fmt::{self, Write}; use style_traits::{CssWriter, KeywordsCollectFn, ParseError}; @@ -23,102 +24,55 @@ use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; #[cfg(feature = "gecko")] fn moz_display_values_enabled(context: &ParserContext) -> bool { - use crate::gecko_bindings::structs; context.in_ua_or_chrome_sheet() || - unsafe { structs::StaticPrefs::sVarCache_layout_css_xul_display_values_content_enabled } + static_prefs::pref!("layout.css.xul-display-values.content.enabled") } #[cfg(feature = "gecko")] fn moz_box_display_values_enabled(context: &ParserContext) -> bool { - use crate::gecko_bindings::structs; context.in_ua_or_chrome_sheet() || - unsafe { - structs::StaticPrefs::sVarCache_layout_css_xul_box_display_values_content_enabled - } -} - -#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] -fn parse_unimplemented_in_servo_2020(_context: &ParserContext) -> bool { - true -} - -#[cfg(feature = "servo-layout-2020")] -fn parse_unimplemented_in_servo_2020(_context: &ParserContext) -> bool { - servo_config::prefs::pref_map() - .get("layout.2020.unimplemented") - .as_bool() - .unwrap_or(false) + static_prefs::pref!("layout.css.xul-box-display-values.content.enabled") } /// 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! #[allow(missing_docs)] -#[derive( - Clone, - Copy, - Debug, - Eq, - FromPrimitive, - Hash, - MallocSizeOf, - Parse, - PartialEq, - SpecifiedValueInfo, - ToComputedValue, - ToCss, - ToResolvedValue, - ToShmem, -)] -#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] +#[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)] #[repr(u8)] -pub enum Display { +pub enum DisplayOutside { None = 0, + Inline, Block, + TableCaption, + InternalTable, + #[cfg(feature = "gecko")] + InternalRuby, #[cfg(feature = "gecko")] + XUL, +} + +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)] +#[repr(u8)] +pub enum DisplayInside { + None = 0, + #[cfg(feature = "gecko")] + Contents, + Block, FlowRoot, Inline, - #[parse(condition = "parse_unimplemented_in_servo_2020")] - InlineBlock, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] - ListItem, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] + Flex, + #[cfg(feature = "gecko")] + Grid, Table, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] - InlineTable, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] TableRowGroup, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] TableColumn, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] TableColumnGroup, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] TableHeaderGroup, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] TableFooterGroup, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] TableRow, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] TableCell, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] - TableCaption, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] - #[parse(aliases = "-webkit-flex")] - Flex, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] - #[parse(aliases = "-webkit-inline-flex")] - InlineFlex, - #[cfg(feature = "gecko")] - Grid, - #[cfg(feature = "gecko")] - InlineGrid, #[cfg(feature = "gecko")] Ruby, #[cfg(feature = "gecko")] @@ -130,46 +84,216 @@ pub enum Display { #[cfg(feature = "gecko")] RubyTextContainer, #[cfg(feature = "gecko")] - Contents, - #[cfg(feature = "gecko")] WebkitBox, #[cfg(feature = "gecko")] - WebkitInlineBox, - #[cfg(feature = "gecko")] - #[parse(condition = "moz_box_display_values_enabled")] MozBox, #[cfg(feature = "gecko")] - #[parse(condition = "moz_box_display_values_enabled")] MozInlineBox, #[cfg(feature = "gecko")] - #[parse(condition = "moz_display_values_enabled")] MozGrid, #[cfg(feature = "gecko")] - #[parse(condition = "moz_display_values_enabled")] MozInlineGrid, #[cfg(feature = "gecko")] - #[parse(condition = "moz_display_values_enabled")] MozGridGroup, #[cfg(feature = "gecko")] - #[parse(condition = "moz_display_values_enabled")] MozGridLine, #[cfg(feature = "gecko")] - #[parse(condition = "moz_display_values_enabled")] MozStack, #[cfg(feature = "gecko")] - #[parse(condition = "moz_display_values_enabled")] MozInlineStack, #[cfg(feature = "gecko")] - #[parse(condition = "moz_display_values_enabled")] MozDeck, #[cfg(feature = "gecko")] - #[parse(condition = "moz_display_values_enabled")] MozGroupbox, #[cfg(feature = "gecko")] - #[parse(condition = "moz_display_values_enabled")] MozPopup, + Flow, // only used for parsing, not computed value +} + +#[allow(missing_docs)] +#[derive( + Clone, + Copy, + Debug, + Eq, + FromPrimitive, + Hash, + MallocSizeOf, + PartialEq, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] +#[repr(transparent)] +pub struct Display(u16); + +/// Gecko-only impl block for Display (shared stuff later in this file): +#[allow(missing_docs)] +#[allow(non_upper_case_globals)] +impl Display { + // Our u16 bits are used as follows: LOOOOOOOIIIIIIII + const LIST_ITEM_BIT: u16 = 0x8000; //^ + const DISPLAY_OUTSIDE_BITS: u16 = 7; // ^^^^^^^ + const DISPLAY_INSIDE_BITS: u16 = 8; // ^^^^^^^^ + + /// https://drafts.csswg.org/css-display/#the-display-properties + pub const None: Self = Self::new(DisplayOutside::None, DisplayInside::None); + #[cfg(feature = "gecko")] + pub const Contents: Self = Self::new(DisplayOutside::None, DisplayInside::Contents); + pub const Inline: Self = Self::new(DisplayOutside::Inline, DisplayInside::Inline); + pub const InlineBlock: Self = Self::new(DisplayOutside::Inline, DisplayInside::FlowRoot); + pub const Block: Self = Self::new(DisplayOutside::Block, DisplayInside::Block); + #[cfg(feature = "gecko")] + pub const FlowRoot: Self = Self::new(DisplayOutside::Block, DisplayInside::FlowRoot); + pub const Flex: Self = Self::new(DisplayOutside::Block, DisplayInside::Flex); + pub const InlineFlex: Self = Self::new(DisplayOutside::Inline, DisplayInside::Flex); + #[cfg(feature = "gecko")] + pub const Grid: Self = Self::new(DisplayOutside::Block, DisplayInside::Grid); + #[cfg(feature = "gecko")] + pub const InlineGrid: Self = Self::new(DisplayOutside::Inline, DisplayInside::Grid); + pub const Table: Self = Self::new(DisplayOutside::Block, DisplayInside::Table); + pub const InlineTable: Self = Self::new(DisplayOutside::Inline, DisplayInside::Table); + pub const TableCaption: Self = Self::new(DisplayOutside::TableCaption, DisplayInside::Block); + #[cfg(feature = "gecko")] + pub const Ruby: Self = Self::new(DisplayOutside::Inline, DisplayInside::Ruby); + #[cfg(feature = "gecko")] + pub const WebkitBox: Self = Self::new(DisplayOutside::Block, DisplayInside::WebkitBox); + #[cfg(feature = "gecko")] + pub const WebkitInlineBox: Self = Self::new(DisplayOutside::Inline, DisplayInside::WebkitBox); + /// Internal table boxes. + pub const TableRowGroup: Self = + Self::new(DisplayOutside::InternalTable, DisplayInside::TableRowGroup); + pub const TableHeaderGroup: Self = Self::new( + DisplayOutside::InternalTable, + DisplayInside::TableHeaderGroup, + ); + pub const TableFooterGroup: Self = Self::new( + DisplayOutside::InternalTable, + DisplayInside::TableFooterGroup, + ); + pub const TableColumn: Self = + Self::new(DisplayOutside::InternalTable, DisplayInside::TableColumn); + pub const TableColumnGroup: Self = Self::new( + DisplayOutside::InternalTable, + DisplayInside::TableColumnGroup, + ); + pub const TableRow: Self = Self::new(DisplayOutside::InternalTable, DisplayInside::TableRow); + + pub const TableCell: Self = Self::new(DisplayOutside::InternalTable, DisplayInside::TableCell); + + /// Internal ruby boxes. + #[cfg(feature = "gecko")] + pub const RubyBase: Self = Self::new(DisplayOutside::InternalRuby, DisplayInside::RubyBase); + #[cfg(feature = "gecko")] + pub const RubyBaseContainer: Self = Self::new( + DisplayOutside::InternalRuby, + DisplayInside::RubyBaseContainer, + ); + #[cfg(feature = "gecko")] + pub const RubyText: Self = Self::new(DisplayOutside::InternalRuby, DisplayInside::RubyText); + #[cfg(feature = "gecko")] + pub const RubyTextContainer: Self = Self::new( + DisplayOutside::InternalRuby, + DisplayInside::RubyTextContainer, + ); + + /// XUL boxes. + #[cfg(feature = "gecko")] + pub const MozBox: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozBox); + #[cfg(feature = "gecko")] + pub const MozInlineBox: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozInlineBox); + #[cfg(feature = "gecko")] + pub const MozGrid: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGrid); + #[cfg(feature = "gecko")] + pub const MozInlineGrid: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozInlineGrid); + #[cfg(feature = "gecko")] + pub const MozGridGroup: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridGroup); + #[cfg(feature = "gecko")] + pub const MozGridLine: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridLine); + #[cfg(feature = "gecko")] + pub const MozStack: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozStack); + #[cfg(feature = "gecko")] + pub const MozInlineStack: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozInlineStack); + #[cfg(feature = "gecko")] + pub const MozDeck: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozDeck); + #[cfg(feature = "gecko")] + pub const MozGroupbox: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGroupbox); + #[cfg(feature = "gecko")] + pub const MozPopup: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozPopup); + + /// Make a raw display value from and values. + #[inline] + const fn new(outside: DisplayOutside, inside: DisplayInside) -> Self { + let o: u16 = ((outside as u8) as u16) << Self::DISPLAY_INSIDE_BITS; + let i: u16 = (inside as u8) as u16; + Self(o | i) + } + + /// Make a display enum value from and values. + /// We store `flow` as a synthetic `block` or `inline` inside-value to simplify + /// our layout code. + #[inline] + fn from3(outside: DisplayOutside, inside: DisplayInside, list_item: bool) -> Self { + let inside = match inside { + DisplayInside::Flow => match outside { + DisplayOutside::Inline => DisplayInside::Inline, + _ => DisplayInside::Block, + }, + _ => inside, + }; + let v = Self::new(outside, inside); + if !list_item { + return v; + } + Self(v.0 | Self::LIST_ITEM_BIT) + } + + /// Accessor for the value. + #[inline] + pub fn inside(&self) -> DisplayInside { + DisplayInside::from_u16(self.0 & ((1 << Self::DISPLAY_INSIDE_BITS) - 1)).unwrap() + } + + /// Accessor for the value. + #[inline] + pub fn outside(&self) -> DisplayOutside { + DisplayOutside::from_u16( + (self.0 >> Self::DISPLAY_INSIDE_BITS) & ((1 << Self::DISPLAY_OUTSIDE_BITS) - 1), + ) + .unwrap() + } + + /// Returns whether this `display` value is some kind of list-item. + #[inline] + pub const fn is_list_item(&self) -> bool { + (self.0 & Self::LIST_ITEM_BIT) != 0 + } + + /// Returns whether this `display` value is a ruby level container. + pub fn is_ruby_level_container(&self) -> bool { + match *self { + #[cfg(feature = "gecko")] + Display::RubyBaseContainer | Display::RubyTextContainer => true, + _ => false, + } + } + + /// Returns whether this `display` value is one of the types for ruby. + pub fn is_ruby_type(&self) -> bool { + match self.inside() { + #[cfg(feature = "gecko")] + DisplayInside::Ruby | + DisplayInside::RubyBase | + DisplayInside::RubyText | + DisplayInside::RubyBaseContainer | + DisplayInside::RubyTextContainer => true, + _ => false, + } + } } +/// Shared Display impl for both Gecko and Servo. +#[allow(non_upper_case_globals)] impl Display { /// The initial display value. #[inline] @@ -183,22 +307,20 @@ impl Display { pub fn is_atomic_inline_level(&self) -> bool { match *self { Display::InlineBlock => true, - #[cfg(feature = "servo-layout-2013")] Display::InlineFlex | Display::InlineTable => true, _ => false, } } - /// Returns whether this "display" value is the display of a flex or + /// Returns whether this `display` value is the display of a flex or /// grid container. /// /// This is used to implement various style fixups. pub fn is_item_container(&self) -> bool { - match *self { - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] - Display::Flex | Display::InlineFlex => true, + match self.inside() { + DisplayInside::Flex => true, #[cfg(feature = "gecko")] - Display::Grid | Display::InlineGrid => true, + DisplayInside::Grid => true, _ => false, } } @@ -215,80 +337,50 @@ impl Display { } } - /// Returns whether this "display" value is one of the types for - /// ruby. - #[cfg(feature = "gecko")] - pub fn is_ruby_type(&self) -> bool { - matches!( - *self, - Display::Ruby | - Display::RubyBase | - Display::RubyText | - Display::RubyBaseContainer | - Display::RubyTextContainer - ) - } - - /// Returns whether this "display" value is a ruby level container. - #[cfg(feature = "gecko")] - pub fn is_ruby_level_container(&self) -> bool { - matches!( - *self, - Display::RubyBaseContainer | Display::RubyTextContainer - ) - } - /// Convert this display into an equivalent block display. /// - /// Also used for style adjustments. + /// Also used for :root style adjustments. pub fn equivalent_block_display(&self, _is_root_element: bool) -> Self { - match *self { - // Values that have a corresponding block-outside version. - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] - Display::InlineTable => Display::Table, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] - Display::InlineFlex => Display::Flex, - - #[cfg(feature = "gecko")] - Display::InlineGrid => Display::Grid, - #[cfg(feature = "gecko")] - Display::WebkitInlineBox => Display::WebkitBox, - - // Special handling for contents and list-item on the root - // element for Gecko. - #[cfg(feature = "gecko")] - Display::Contents | Display::ListItem if _is_root_element => Display::Block, - - // These are not changed by blockification. - Display::None | Display::Block => *self, - #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] - Display::Flex | Display::ListItem | Display::Table => *self, - - #[cfg(feature = "gecko")] - Display::Contents | Display::FlowRoot | Display::Grid | Display::WebkitBox => *self, + #[cfg(feature = "gecko")] + { + // Special handling for `contents` and `list-item`s on the root element. + if _is_root_element && (self.is_contents() || self.is_list_item()) { + return Display::Block; + } + } - // Everything else becomes block. + match self.outside() { + DisplayOutside::Inline => { + let inside = match self.inside() { + DisplayInside::Inline | DisplayInside::FlowRoot => DisplayInside::Block, + inside => inside, + }; + Display::from3(DisplayOutside::Block, inside, self.is_list_item()) + }, + DisplayOutside::Block | DisplayOutside::None => *self, _ => Display::Block, } } - /// Convert this display into an inline-outside display. - /// - /// Ideally it should implement spec: https://drafts.csswg.org/css-display/#inlinify - /// but the spec isn't stable enough, so we copy what Gecko does for now. + /// Convert this display into an equivalent inline-outside display. + /// https://drafts.csswg.org/css-display/#inlinify #[cfg(feature = "gecko")] pub fn inlinify(&self) -> Self { - match *self { - Display::Block | Display::FlowRoot => Display::InlineBlock, - Display::Table => Display::InlineTable, - Display::Flex => Display::InlineFlex, - Display::Grid => Display::InlineGrid, - // XXX bug 1105868 this should probably be InlineListItem: - Display::ListItem => Display::Inline, - Display::MozBox => Display::MozInlineBox, - Display::MozStack => Display::MozInlineStack, - Display::WebkitBox => Display::WebkitInlineBox, - other => other, + match self.outside() { + DisplayOutside::Block => { + let inside = match self.inside() { + DisplayInside::Block => DisplayInside::FlowRoot, + inside => inside, + }; + Display::from3(DisplayOutside::Inline, inside, self.is_list_item()) + }, + #[cfg(feature = "gecko")] + DisplayOutside::XUL => match self.inside() { + DisplayInside::MozBox => Display::MozInlineBox, + DisplayInside::MozStack => Display::MozInlineStack, + _ => *self, + }, + _ => *self, } } @@ -309,6 +401,263 @@ impl Display { } } +impl ToCss for Display { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: fmt::Write, + { + debug_assert_ne!( + self.inside(), + DisplayInside::Flow, + "`flow` never appears in `display` computed value" + ); + let outside = self.outside(); + let inside = match self.inside() { + DisplayInside::Block | DisplayInside::Inline => DisplayInside::Flow, + inside => inside, + }; + match *self { + Display::Block | Display::Inline => outside.to_css(dest), + Display::InlineBlock => dest.write_str("inline-block"), + #[cfg(feature = "gecko")] + Display::WebkitInlineBox => dest.write_str("-webkit-inline-box"), + #[cfg(feature = "gecko")] + Display::MozInlineBox => dest.write_str("-moz-inline-box"), + #[cfg(feature = "gecko")] + Display::MozInlineGrid => dest.write_str("-moz-inline-grid"), + #[cfg(feature = "gecko")] + Display::MozInlineStack => dest.write_str("-moz-inline-stack"), + Display::TableCaption => dest.write_str("table-caption"), + _ => match (outside, inside) { + #[cfg(feature = "gecko")] + (DisplayOutside::Inline, DisplayInside::Grid) => dest.write_str("inline-grid"), + (DisplayOutside::Inline, DisplayInside::Flex) | + (DisplayOutside::Inline, DisplayInside::Table) => { + dest.write_str("inline-")?; + inside.to_css(dest) + }, + #[cfg(feature = "gecko")] + (DisplayOutside::Block, DisplayInside::Ruby) => dest.write_str("block ruby"), + (_, inside) => { + if self.is_list_item() { + if outside != DisplayOutside::Block { + outside.to_css(dest)?; + dest.write_str(" ")?; + } + if inside != DisplayInside::Flow { + inside.to_css(dest)?; + dest.write_str(" ")?; + } + dest.write_str("list-item") + } else { + inside.to_css(dest) + } + }, + }, + } + } +} + +/// = flow | flow-root | table | flex | grid | ruby +/// https://drafts.csswg.org/css-display/#typedef-display-inside +fn parse_display_inside<'i, 't>( + input: &mut Parser<'i, 't>, +) -> Result> { + Ok(try_match_ident_ignore_ascii_case! { input, + "flow" => DisplayInside::Flow, + #[cfg(feature = "gecko")] + "flow-root" => DisplayInside::FlowRoot, + "table" => DisplayInside::Table, + "flex" => DisplayInside::Flex, + #[cfg(feature = "gecko")] + "grid" => DisplayInside::Grid, + #[cfg(feature = "gecko")] + "ruby" => DisplayInside::Ruby, + }) +} + +/// = block | inline | run-in +/// https://drafts.csswg.org/css-display/#typedef-display-outside +fn parse_display_outside<'i, 't>( + input: &mut Parser<'i, 't>, +) -> Result> { + Ok(try_match_ident_ignore_ascii_case! { input, + "block" => DisplayOutside::Block, + "inline" => DisplayOutside::Inline, + // FIXME(bug 2056): not supported in layout yet: + //"run-in" => DisplayOutside::RunIn, + }) +} + +/// (flow | flow-root)? +fn parse_display_inside_for_list_item<'i, 't>( + input: &mut Parser<'i, 't>, +) -> Result> { + Ok(try_match_ident_ignore_ascii_case! { input, + "flow" => DisplayInside::Flow, + #[cfg(feature = "gecko")] + "flow-root" => DisplayInside::FlowRoot, + }) +} +/// Test a Result for same values as above. +fn is_valid_inside_for_list_item<'i>(inside: &Result>) -> bool { + match inside { + Ok(DisplayInside::Flow) => true, + #[cfg(feature = "gecko")] + Ok(DisplayInside::FlowRoot) => true, + _ => false, + } +} + +/// Parse `list-item`. +fn parse_list_item<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(), ParseError<'i>> { + Ok(try_match_ident_ignore_ascii_case! { input, + "list-item" => (), + }) +} + +impl Parse for Display { + #[allow(unused)] // `context` isn't used for servo-2020 for now + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + // Parse all combinations of ? and `list-item`? first. + let mut got_list_item = input.try(parse_list_item).is_ok(); + let mut inside = if got_list_item { + input.try(parse_display_inside_for_list_item) + } else { + input.try(parse_display_inside) + }; + // = ? && [ flow | flow-root ]? && list-item + // https://drafts.csswg.org/css-display/#typedef-display-listitem + if !got_list_item && is_valid_inside_for_list_item(&inside) { + got_list_item = input.try(parse_list_item).is_ok(); + } + let outside = input.try(parse_display_outside); + if outside.is_ok() { + if !got_list_item && (inside.is_err() || is_valid_inside_for_list_item(&inside)) { + got_list_item = input.try(parse_list_item).is_ok(); + } + if inside.is_err() { + inside = if got_list_item { + input.try(parse_display_inside_for_list_item) + } else { + input.try(parse_display_inside) + }; + if !got_list_item && is_valid_inside_for_list_item(&inside) { + got_list_item = input.try(parse_list_item).is_ok(); + } + } + } + if got_list_item || inside.is_ok() || outside.is_ok() { + let inside = inside.unwrap_or(DisplayInside::Flow); + let outside = outside.unwrap_or(match inside { + // "If is omitted, the element’s outside display type + // defaults to block — except for ruby, which defaults to inline." + // https://drafts.csswg.org/css-display/#inside-model + #[cfg(feature = "gecko")] + DisplayInside::Ruby => DisplayOutside::Inline, + _ => DisplayOutside::Block, + }); + return Ok(Display::from3(outside, inside, got_list_item)); + } + + // Now parse the single-keyword `display` values. + Ok(try_match_ident_ignore_ascii_case! { input, + "none" => Display::None, + #[cfg(feature = "gecko")] + "contents" => Display::Contents, + "inline-block" => Display::InlineBlock, + "inline-table" => Display::InlineTable, + "-webkit-flex" => Display::Flex, + "inline-flex" | "-webkit-inline-flex" => Display::InlineFlex, + #[cfg(feature = "gecko")] + "inline-grid" => Display::InlineGrid, + "table-caption" => Display::TableCaption, + "table-row-group" => Display::TableRowGroup, + "table-header-group" => Display::TableHeaderGroup, + "table-footer-group" => Display::TableFooterGroup, + "table-column" => Display::TableColumn, + "table-column-group" => Display::TableColumnGroup, + "table-row" => Display::TableRow, + "table-cell" => Display::TableCell, + #[cfg(feature = "gecko")] + "ruby-base" => Display::RubyBase, + #[cfg(feature = "gecko")] + "ruby-base-container" => Display::RubyBaseContainer, + #[cfg(feature = "gecko")] + "ruby-text" => Display::RubyText, + #[cfg(feature = "gecko")] + "ruby-text-container" => Display::RubyTextContainer, + #[cfg(feature = "gecko")] + "-webkit-box" => Display::WebkitBox, + #[cfg(feature = "gecko")] + "-webkit-inline-box" => Display::WebkitInlineBox, + #[cfg(feature = "gecko")] + "-moz-box" if moz_box_display_values_enabled(context) => Display::MozBox, + #[cfg(feature = "gecko")] + "-moz-inline-box" if moz_box_display_values_enabled(context) => Display::MozInlineBox, + #[cfg(feature = "gecko")] + "-moz-grid" if moz_display_values_enabled(context) => Display::MozGrid, + #[cfg(feature = "gecko")] + "-moz-inline-grid" if moz_display_values_enabled(context) => Display::MozInlineGrid, + #[cfg(feature = "gecko")] + "-moz-grid-group" if moz_display_values_enabled(context) => Display::MozGridGroup, + #[cfg(feature = "gecko")] + "-moz-grid-line" if moz_display_values_enabled(context) => Display::MozGridLine, + #[cfg(feature = "gecko")] + "-moz-stack" if moz_display_values_enabled(context) => Display::MozStack, + #[cfg(feature = "gecko")] + "-moz-inline-stack" if moz_display_values_enabled(context) => Display::MozInlineStack, + #[cfg(feature = "gecko")] + "-moz-deck" if moz_display_values_enabled(context) => Display::MozDeck, + #[cfg(feature = "gecko")] + "-moz-groupbox" if moz_display_values_enabled(context) => Display::MozGroupbox, + #[cfg(feature = "gecko")] + "-moz-popup" if moz_display_values_enabled(context) => Display::MozPopup, + }) + } +} + +impl SpecifiedValueInfo for Display { + fn collect_completion_keywords(f: KeywordsCollectFn) { + f(&[ + "block", + "contents", + "flex", + "flow-root", + "grid", + "inline", + "inline-block", + "inline-flex", + "inline-grid", + "inline-table", + "inline list-item", + "inline flow-root list-item", + "list-item", + "none", + "block ruby", + "ruby", + "ruby-base", + "ruby-base-container", + "ruby-text", + "ruby-text-container", + "table", + "table-caption", + "table-cell", + "table-column", + "table-column-group", + "table-footer-group", + "table-header-group", + "table-row", + "table-row-group", + "-webkit-box", + "-webkit-inline-box", + ]); + } +} + /// A specified value for the `vertical-align` property. pub type VerticalAlign = GenericVerticalAlign; diff --git a/components/style/values/specified/grid.rs b/components/style/values/specified/grid.rs index 3e7f8f72a003..b75e97aca99c 100644 --- a/components/style/values/specified/grid.rs +++ b/components/style/values/specified/grid.rs @@ -6,10 +6,9 @@ //! [grids](https://drafts.csswg.org/css-grid/) use crate::parser::{Parse, ParserContext}; -use crate::values::computed::{self, Context, ToComputedValue}; -use crate::values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth}; -use crate::values::generics::grid::{LineNameList, TrackRepeat, TrackSize}; -use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue}; +use crate::values::generics::grid::{GridTemplateComponent, ImplicitGridTracks, RepeatCount}; +use crate::values::generics::grid::{LineNameList, TrackBreadth, TrackRepeat, TrackSize}; +use crate::values::generics::grid::{TrackList, TrackListValue}; use crate::values::specified::{Integer, LengthPercentage}; use crate::values::{CSSFloat, CustomIdent}; use cssparser::{ParseError as CssParseError, Parser, Token}; @@ -96,12 +95,27 @@ impl Parse for TrackSize { } } +impl Parse for ImplicitGridTracks> { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + use style_traits::{Separator, Space}; + let track_sizes = Space::parse(input, |i| TrackSize::parse(context, i))?; + if track_sizes.len() == 1 && track_sizes[0].is_auto() { + //`auto`, which is the initial value, is always represented by an empty slice. + return Ok(Default::default()); + } + return Ok(ImplicitGridTracks(track_sizes.into())); + } +} + /// Parse the grid line names into a vector of owned strings. /// /// pub fn parse_line_names<'i, 't>( input: &mut Parser<'i, 't>, -) -> Result, ParseError<'i>> { +) -> Result, ParseError<'i>> { input.expect_square_bracket_block()?; input.parse_nested_block(|input| { let mut values = vec![]; @@ -112,7 +126,7 @@ pub fn parse_line_names<'i, 't>( values.push(ident); } - Ok(values.into_boxed_slice()) + Ok(values.into()) }) } @@ -155,9 +169,7 @@ impl TrackRepeat { let mut current_names; loop { - current_names = input - .try(parse_line_names) - .unwrap_or(vec![].into_boxed_slice()); + current_names = input.try(parse_line_names).unwrap_or_default(); if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) { if !track_size.is_fixed() { if is_auto { @@ -180,11 +192,7 @@ impl TrackRepeat { // one `TrackSize`. But in current version of the spec, this is deprecated // but we are adding this for gecko parity. We should remove this when // gecko implements new spec. - names.push( - input - .try(parse_line_names) - .unwrap_or(vec![].into_boxed_slice()), - ); + names.push(input.try(parse_line_names).unwrap_or_default()); break; } } else { @@ -201,9 +209,9 @@ impl TrackRepeat { } let repeat = TrackRepeat { - count: count, - track_sizes: values, - line_names: names.into_boxed_slice(), + count, + track_sizes: values.into(), + line_names: names.into(), }; Ok((repeat, repeat_type)) @@ -221,47 +229,31 @@ impl Parse for TrackList { let mut names = vec![]; let mut values = vec![]; - // assume it's the simplest case. - let mut list_type = TrackListType::Explicit; - // holds value. It can only be only one in a TrackList. - let mut auto_repeat = None; - // if there is any the list will be of type TrackListType::Auto(idx) - // where idx points to the position of the in the track list. If there - // is any repeat before , we need to take the number of repetitions into - // account to set the position of so it remains the same while computing - // values. - let mut auto_offset = 0; + // Whether we've parsed an `` value. + let mut auto_repeat_index = None; // assume that everything is . This flag is useful when we encounter - let mut atleast_one_not_fixed = false; + let mut at_least_one_not_fixed = false; loop { - current_names.extend_from_slice( - &mut input - .try(parse_line_names) - .unwrap_or(vec![].into_boxed_slice()), - ); + current_names.extend_from_slice(&mut input.try(parse_line_names).unwrap_or_default()); if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) { if !track_size.is_fixed() { - atleast_one_not_fixed = true; - if auto_repeat.is_some() { + at_least_one_not_fixed = true; + if auto_repeat_index.is_some() { // only accepts and return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); } } let vec = mem::replace(&mut current_names, vec![]); - names.push(vec.into_boxed_slice()); + names.push(vec.into()); values.push(TrackListValue::TrackSize(track_size)); } else if let Ok((repeat, type_)) = input.try(|i| TrackRepeat::parse_with_repeat_type(context, i)) { - if list_type == TrackListType::Explicit { - list_type = TrackListType::Normal; // doesn't contain repeat() - } - match type_ { RepeatType::Normal => { - atleast_one_not_fixed = true; - if auto_repeat.is_some() { + at_least_one_not_fixed = true; + if auto_repeat_index.is_some() { // only return Err( input.new_custom_error(StyleParseErrorKind::UnspecifiedError) @@ -269,137 +261,42 @@ impl Parse for TrackList { } }, RepeatType::Auto => { - if auto_repeat.is_some() || atleast_one_not_fixed { + if auto_repeat_index.is_some() || at_least_one_not_fixed { // We've either seen earlier, or there's at least one non-fixed value return Err( input.new_custom_error(StyleParseErrorKind::UnspecifiedError) ); } - - list_type = TrackListType::Auto(values.len() as u16 + auto_offset); - auto_repeat = Some(repeat); - let vec = mem::replace(&mut current_names, vec![]); - names.push(vec.into_boxed_slice()); - continue; + auto_repeat_index = Some(values.len()); }, - RepeatType::Fixed => (), + RepeatType::Fixed => {}, } let vec = mem::replace(&mut current_names, vec![]); - names.push(vec.into_boxed_slice()); - if let RepeatCount::Number(num) = repeat.count { - auto_offset += (num.value() - 1) as u16; - } + names.push(vec.into()); values.push(TrackListValue::TrackRepeat(repeat)); } else { - if values.is_empty() && auto_repeat.is_none() { + if values.is_empty() && auto_repeat_index.is_none() { return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); } - names.push(current_names.into_boxed_slice()); + names.push(current_names.into()); break; } } Ok(TrackList { - list_type: list_type, - values: values, - line_names: names.into_boxed_slice(), - auto_repeat: auto_repeat, + auto_repeat_index: auto_repeat_index.unwrap_or(std::usize::MAX), + values: values.into(), + line_names: names.into(), }) } } -impl ToComputedValue for TrackList { - type ComputedValue = TrackList; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - // Merge the line names while computing values. The resulting values will - // all be bunch of `` and one . - // - // For example, - // `[a b] 100px [c d] repeat(1, 30px [g]) [h]` will be merged as `[a b] 100px [c d] 30px [g h]` - // whereas, `[a b] repeat(2, [c] 50px [d]) [e f] repeat(auto-fill, [g] 12px) 10px [h]` will be merged as - // `[a b c] 50px [d c] 50px [d e f] repeat(auto-fill, [g] 12px) 10px [h]`, with the `` value - // set in the `auto_repeat` field, and the `idx` in TrackListType::Auto pointing to the values after - // `` (in this case, `10px [h]`). - let mut prev_names = vec![]; - let mut line_names = Vec::with_capacity(self.line_names.len() + 1); - let mut values = Vec::with_capacity(self.values.len() + 1); - for (pos, names) in self.line_names.iter().enumerate() { - prev_names.extend_from_slice(&names); - if pos >= self.values.len() { - let vec = mem::replace(&mut prev_names, vec![]); - line_names.push(vec.into_boxed_slice()); - continue; - } - - match self.values[pos] { - TrackListValue::TrackSize(ref size) => { - let vec = mem::replace(&mut prev_names, vec![]); - line_names.push(vec.into_boxed_slice()); - values.push(TrackListValue::TrackSize(size.to_computed_value(context))); - }, - TrackListValue::TrackRepeat(ref repeat) => { - // If the repeat count is numeric, we expand and merge the values. - let mut repeat = repeat.expand(); - let mut repeat_names_iter = repeat.line_names.iter(); - for (size, repeat_names) in - repeat.track_sizes.drain(..).zip(&mut repeat_names_iter) - { - prev_names.extend_from_slice(&repeat_names); - let vec = mem::replace(&mut prev_names, vec![]); - line_names.push(vec.into_boxed_slice()); - values.push(TrackListValue::TrackSize(size.to_computed_value(context))); - } - - if let Some(names) = repeat_names_iter.next() { - prev_names.extend_from_slice(&names); - } - }, - } - } - - TrackList { - list_type: self.list_type.to_computed_value(context), - values: values, - line_names: line_names.into_boxed_slice(), - auto_repeat: self - .auto_repeat - .clone() - .map(|repeat| repeat.to_computed_value(context)), - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - let mut values = Vec::with_capacity(computed.values.len() + 1); - for value in computed - .values - .iter() - .map(ToComputedValue::from_computed_value) - { - values.push(value); - } - - TrackList { - list_type: computed.list_type, - values: values, - line_names: computed.line_names.clone(), - auto_repeat: computed - .auto_repeat - .clone() - .map(|ref repeat| TrackRepeat::from_computed_value(repeat)), - } - } -} - #[cfg(feature = "gecko")] #[inline] fn allow_grid_template_subgrids() -> bool { - use crate::gecko_bindings::structs::mozilla; - unsafe { mozilla::StaticPrefs::sVarCache_layout_css_grid_template_subgrid_value_enabled } + static_prefs::pref!("layout.css.grid-template-subgrid-value.enabled") } #[cfg(feature = "servo")] @@ -409,7 +306,6 @@ fn allow_grid_template_subgrids() -> bool { } impl Parse for GridTemplateComponent { - // FIXME: Derive Parse (probably with None_) fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, @@ -430,10 +326,11 @@ impl GridTemplateComponent { ) -> Result> { if allow_grid_template_subgrids() { if let Ok(t) = input.try(|i| LineNameList::parse(context, i)) { - return Ok(GridTemplateComponent::Subgrid(t)); + return Ok(GridTemplateComponent::Subgrid(Box::new(t))); } } - TrackList::parse(context, input).map(GridTemplateComponent::TrackList) + let track_list = TrackList::parse(context, input)?; + Ok(GridTemplateComponent::TrackList(Box::new(track_list))) } } diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index f33a191c2773..16897043da95 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -8,6 +8,7 @@ use super::computed::transform::DirectionVector; use super::computed::{Context, ToComputedValue}; +use super::generics::grid::ImplicitGridTracks as GenericImplicitGridTracks; use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth}; use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize}; use super::generics::transform::IsParallelTo; @@ -69,7 +70,7 @@ pub use self::list::Quotes; pub use self::motion::{OffsetPath, OffsetRotate}; pub use self::outline::OutlineStyle; pub use self::percentage::Percentage; -pub use self::position::{GridAutoFlow, GridTemplateAreas, Position}; +pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, PositionOrAuto}; pub use self::position::{PositionComponent, ZIndex}; pub use self::rect::NonNegativeLengthOrNumberRect; pub use self::resolution::Resolution; @@ -81,7 +82,7 @@ pub use self::table::XSpan; pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAlign}; pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak}; pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing}; -pub use self::text::{TextDecorationSkipInk, TextTransform}; +pub use self::text::{TextDecorationLength, TextDecorationSkipInk, TextTransform}; pub use self::time::Time; pub use self::transform::{Rotate, Scale, Transform}; pub use self::transform::{TransformOrigin, TransformStyle, Translate}; @@ -626,6 +627,9 @@ pub type TrackBreadth = GenericTrackBreadth; /// The specified value of a grid `` pub type TrackSize = GenericTrackSize; +/// The specified value of a grid `+` +pub type ImplicitGridTracks = GenericImplicitGridTracks; + /// The specified value of a grid `` /// (could also be `` or ``) pub type TrackList = GenericTrackList; diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs index 4e6a71ec2cad..ce3bab1047be 100644 --- a/components/style/values/specified/position.rs +++ b/components/style/values/specified/position.rs @@ -13,6 +13,7 @@ use crate::str::HTML_SPACE_CHARACTERS; use crate::values::computed::LengthPercentage as ComputedLengthPercentage; use crate::values::computed::{Context, Percentage, ToComputedValue}; use crate::values::generics::position::Position as GenericPosition; +use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto; use crate::values::generics::position::ZIndex as GenericZIndex; use crate::values::specified::{AllowQuirks, Integer, LengthPercentage}; use crate::Atom; @@ -26,6 +27,9 @@ use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; /// The specified value of a CSS `` pub type Position = GenericPosition; +/// The specified value of an `auto | `. +pub type PositionOrAuto = GenericPositionOrAuto; + /// The specified value of a horizontal position. pub type HorizontalPosition = PositionComponent; diff --git a/components/style/values/specified/svg.rs b/components/style/values/specified/svg.rs index 9279707935fe..4858fbaec6b9 100644 --- a/components/style/values/specified/svg.rs +++ b/components/style/values/specified/svg.rs @@ -32,8 +32,7 @@ pub type SVGStrokeDashArray = generic::SVGStrokeDashArray bool { - use crate::gecko_bindings::structs::mozilla; - unsafe { mozilla::StaticPrefs::sVarCache_gfx_font_rendering_opentype_svg_enabled } + static_prefs::pref!("gfx.font_rendering.opentype_svg.enabled") } /// Whether the `context-value` value is enabled. diff --git a/components/style/values/specified/svg_path.rs b/components/style/values/specified/svg_path.rs index e5282e0a1646..4f49029b51ea 100644 --- a/components/style/values/specified/svg_path.rs +++ b/components/style/values/specified/svg_path.rs @@ -625,40 +625,26 @@ impl<'a> PathParser<'a> { break; } - match self.chars.next() { - Some(command) => { - let abs = if command.is_ascii_uppercase() { - IsAbsolute::Yes - } else { - IsAbsolute::No - }; - macro_rules! parse_command { - ( $($($p:pat)|+ => $parse_func:ident,)* ) => { - match command { - $( - $($p)|+ => { - skip_wsp(&mut self.chars); - self.$parse_func(abs)?; - }, - )* - _ => return Err(()), - } - } - } - parse_command!( - b'Z' | b'z' => parse_closepath, - b'L' | b'l' => parse_lineto, - b'H' | b'h' => parse_h_lineto, - b'V' | b'v' => parse_v_lineto, - b'C' | b'c' => parse_curveto, - b'S' | b's' => parse_smooth_curveto, - b'Q' | b'q' => parse_quadratic_bezier_curveto, - b'T' | b't' => parse_smooth_quadratic_bezier_curveto, - b'A' | b'a' => parse_elliptical_arc, - ); - }, - _ => break, // no more commands. - } + let command = self.chars.next().unwrap(); + let abs = if command.is_ascii_uppercase() { + IsAbsolute::Yes + } else { + IsAbsolute::No + }; + + skip_wsp(&mut self.chars); + match command { + b'Z' | b'z' => self.parse_closepath(), + b'L' | b'l' => self.parse_lineto(abs), + b'H' | b'h' => self.parse_h_lineto(abs), + b'V' | b'v' => self.parse_v_lineto(abs), + b'C' | b'c' => self.parse_curveto(abs), + b'S' | b's' => self.parse_smooth_curveto(abs), + b'Q' | b'q' => self.parse_quadratic_bezier_curveto(abs), + b'T' | b't' => self.parse_smooth_quadratic_bezier_curveto(abs), + b'A' | b'a' => self.parse_elliptical_arc(abs), + _ => return Err(()), + }?; } Ok(()) } @@ -692,7 +678,7 @@ impl<'a> PathParser<'a> { } /// Parse "closepath" command. - fn parse_closepath(&mut self, _absolute: IsAbsolute) -> Result<(), ()> { + fn parse_closepath(&mut self) -> Result<(), ()> { self.path.push(PathCommand::ClosePath); Ok(()) } diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index c66e93803f6e..1686b9f424dc 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -7,13 +7,12 @@ use crate::parser::{Parse, ParserContext}; use crate::properties::longhands::writing_mode::computed_value::T as SpecifiedWritingMode; use crate::values::computed::text::LineHeight as ComputedLineHeight; -use crate::values::computed::text::TextEmphasisKeywordValue as ComputedTextEmphasisKeywordValue; use crate::values::computed::text::TextEmphasisStyle as ComputedTextEmphasisStyle; use crate::values::computed::text::TextOverflow as ComputedTextOverflow; use crate::values::computed::{Context, ToComputedValue}; use crate::values::generics::text::InitialLetter as GenericInitialLetter; use crate::values::generics::text::LineHeight as GenericLineHeight; -use crate::values::generics::text::Spacing; +use crate::values::generics::text::{GenericTextDecorationLength, Spacing}; use crate::values::specified::length::NonNegativeLengthPercentage; use crate::values::specified::length::{FontRelativeLength, Length}; use crate::values::specified::length::{LengthPercentage, NoCalcLength}; @@ -645,48 +644,34 @@ impl ToComputedValue for TextAlign { } } +fn fill_mode_is_default_and_shape_exists( + fill: &TextEmphasisFillMode, + shape: &Option, +) -> bool { + shape.is_some() && fill.is_filled() +} + /// Specified value of text-emphasis-style property. +/// +/// https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-style #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] +#[allow(missing_docs)] pub enum TextEmphasisStyle { - /// - Keyword(TextEmphasisKeywordValue), + /// [ || ] + Keyword { + #[css(contextual_skip_if = "fill_mode_is_default_and_shape_exists")] + fill: TextEmphasisFillMode, + shape: Option, + }, /// `none` None, - /// String (will be used only first grapheme cluster) for the text-emphasis-style property - String(String), -} - -/// Keyword value for the text-emphasis-style property -#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] -pub enum TextEmphasisKeywordValue { - /// - Fill(TextEmphasisFillMode), - /// - Shape(TextEmphasisShapeKeyword), - /// - FillAndShape(TextEmphasisFillMode, TextEmphasisShapeKeyword), -} - -impl TextEmphasisKeywordValue { - fn fill(&self) -> Option { - match *self { - TextEmphasisKeywordValue::Fill(fill) | - TextEmphasisKeywordValue::FillAndShape(fill, _) => Some(fill), - _ => None, - } - } - - fn shape(&self) -> Option { - match *self { - TextEmphasisKeywordValue::Shape(shape) | - TextEmphasisKeywordValue::FillAndShape(_, shape) => Some(shape), - _ => None, - } - } + /// `` (of which only the first grapheme cluster will be used). + String(crate::OwnedStr), } /// Fill mode for the text-emphasis-style property #[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] +#[repr(u8)] pub enum TextEmphasisFillMode { /// `filled` Filled, @@ -694,10 +679,19 @@ pub enum TextEmphasisFillMode { Open, } +impl TextEmphasisFillMode { + /// Whether the value is `filled`. + #[inline] + pub fn is_filled(&self) -> bool { + matches!(*self, TextEmphasisFillMode::Filled) + } +} + /// Shape keyword for the text-emphasis-style property #[derive( Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, )] +#[repr(u8)] pub enum TextEmphasisShapeKeyword { /// `dot` Dot, @@ -711,77 +705,39 @@ pub enum TextEmphasisShapeKeyword { Sesame, } -impl TextEmphasisShapeKeyword { - /// converts fill mode to a unicode char - pub fn char(&self, fill: TextEmphasisFillMode) -> &str { - let fill = fill == TextEmphasisFillMode::Filled; - match *self { - TextEmphasisShapeKeyword::Dot => { - if fill { - "\u{2022}" - } else { - "\u{25e6}" - } - }, - TextEmphasisShapeKeyword::Circle => { - if fill { - "\u{25cf}" - } else { - "\u{25cb}" - } - }, - TextEmphasisShapeKeyword::DoubleCircle => { - if fill { - "\u{25c9}" - } else { - "\u{25ce}" - } - }, - TextEmphasisShapeKeyword::Triangle => { - if fill { - "\u{25b2}" - } else { - "\u{25b3}" - } - }, - TextEmphasisShapeKeyword::Sesame => { - if fill { - "\u{fe45}" - } else { - "\u{fe46}" - } - }, - } - } -} - impl ToComputedValue for TextEmphasisStyle { type ComputedValue = ComputedTextEmphasisStyle; #[inline] fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { match *self { - TextEmphasisStyle::Keyword(ref keyword) => { - // FIXME(emilio): This should set the rule_cache_conditions - // properly. - let default_shape = if context.style().get_inherited_box().clone_writing_mode() == - SpecifiedWritingMode::HorizontalTb - { - TextEmphasisShapeKeyword::Circle - } else { - TextEmphasisShapeKeyword::Sesame - }; - ComputedTextEmphasisStyle::Keyword(ComputedTextEmphasisKeywordValue { - fill: keyword.fill().unwrap_or(TextEmphasisFillMode::Filled), - shape: keyword.shape().unwrap_or(default_shape), - }) + TextEmphasisStyle::Keyword { fill, shape } => { + let shape = shape.unwrap_or_else(|| { + // FIXME(emilio, bug 1572958): This should set the + // rule_cache_conditions properly. + // + // Also should probably use WritingMode::is_vertical rather + // than the computed value of the `writing-mode` property. + if context.style().get_inherited_box().clone_writing_mode() == + SpecifiedWritingMode::HorizontalTb + { + TextEmphasisShapeKeyword::Circle + } else { + TextEmphasisShapeKeyword::Sesame + } + }); + ComputedTextEmphasisStyle::Keyword { fill, shape } }, TextEmphasisStyle::None => ComputedTextEmphasisStyle::None, TextEmphasisStyle::String(ref s) => { // Passing `true` to iterate over extended grapheme clusters, following // recommendation at http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries - let string = s.graphemes(true).next().unwrap_or("").to_string(); - ComputedTextEmphasisStyle::String(string) + // + // FIXME(emilio): Doing this at computed value time seems wrong. + // The spec doesn't say that this should be a computed-value + // time operation. This is observable from getComputedStyle(). + let s = s.graphemes(true).next().unwrap_or("").to_string(); + ComputedTextEmphasisStyle::String(s.into()) }, } } @@ -789,9 +745,10 @@ impl ToComputedValue for TextEmphasisStyle { #[inline] fn from_computed_value(computed: &Self::ComputedValue) -> Self { match *computed { - ComputedTextEmphasisStyle::Keyword(ref keyword) => TextEmphasisStyle::Keyword( - TextEmphasisKeywordValue::FillAndShape(keyword.fill, keyword.shape), - ), + ComputedTextEmphasisStyle::Keyword { fill, shape } => TextEmphasisStyle::Keyword { + fill, + shape: Some(shape), + }, ComputedTextEmphasisStyle::None => TextEmphasisStyle::None, ComputedTextEmphasisStyle::String(ref string) => { TextEmphasisStyle::String(string.clone()) @@ -814,7 +771,7 @@ impl Parse for TextEmphasisStyle { if let Ok(s) = input.try(|i| i.expect_string().map(|s| s.as_ref().to_owned())) { // Handle - return Ok(TextEmphasisStyle::String(s)); + return Ok(TextEmphasisStyle::String(s.into())); } // Handle a pair of keywords @@ -824,14 +781,17 @@ impl Parse for TextEmphasisStyle { shape = input.try(TextEmphasisShapeKeyword::parse).ok(); } - // At least one of shape or fill must be handled - let keyword_value = match (fill, shape) { - (Some(fill), Some(shape)) => TextEmphasisKeywordValue::FillAndShape(fill, shape), - (Some(fill), None) => TextEmphasisKeywordValue::Fill(fill), - (None, Some(shape)) => TextEmphasisKeywordValue::Shape(shape), - _ => return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)), - }; - Ok(TextEmphasisStyle::Keyword(keyword_value)) + if shape.is_none() && fill.is_none() { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + + // If a shape keyword is specified but neither filled nor open is + // specified, filled is assumed. + let fill = fill.unwrap_or(TextEmphasisFillMode::Filled); + + // We cannot do the same because the default `` depends on the + // computed writing-mode. + Ok(TextEmphasisStyle::Keyword { fill, shape }) } } @@ -1079,3 +1039,20 @@ pub enum TextDecorationSkipInk { Auto, None, } + +/// Implements type for `text-underline-offset` and `text-decoration-thickness` properties +pub type TextDecorationLength = GenericTextDecorationLength; + +impl TextDecorationLength { + /// `Auto` value. + #[inline] + pub fn auto() -> Self { + GenericTextDecorationLength::Auto + } + + /// Whether this is the `Auto` value. + #[inline] + pub fn is_auto(&self) -> bool { + matches!(*self, GenericTextDecorationLength::Auto) + } +} diff --git a/components/style/values/specified/ui.rs b/components/style/values/specified/ui.rs index 0cc20d960c6e..46272b2ae851 100644 --- a/components/style/values/specified/ui.rs +++ b/components/style/values/specified/ui.rs @@ -199,7 +199,9 @@ pub enum CursorKind { Move, NoDrop, NotAllowed, + #[parse(aliases = "-moz-grab")] Grab, + #[parse(aliases = "-moz-grabbing")] Grabbing, EResize, NResize, @@ -216,15 +218,9 @@ pub enum CursorKind { ColResize, RowResize, AllScroll, + #[parse(aliases = "-moz-zoom-in")] ZoomIn, + #[parse(aliases = "-moz-zoom-out")] ZoomOut, Auto, - #[cfg(feature = "gecko")] - MozGrab, - #[cfg(feature = "gecko")] - MozGrabbing, - #[cfg(feature = "gecko")] - MozZoomIn, - #[cfg(feature = "gecko")] - MozZoomOut, } diff --git a/components/style_traits/specified_value_info.rs b/components/style_traits/specified_value_info.rs index 39740bc72621..1dd368d36e9c 100644 --- a/components/style_traits/specified_value_info.rs +++ b/components/style_traits/specified_value_info.rs @@ -82,6 +82,7 @@ impl SpecifiedValueInfo for i32 {} impl SpecifiedValueInfo for u8 {} impl SpecifiedValueInfo for u16 {} impl SpecifiedValueInfo for u32 {} +impl SpecifiedValueInfo for usize {} impl SpecifiedValueInfo for str {} impl SpecifiedValueInfo for String {} impl SpecifiedValueInfo for crate::owned_str::OwnedStr {} diff --git a/servo-tidy.toml b/servo-tidy.toml index 42a253b1aa7c..cedd07f27116 100644 --- a/servo-tidy.toml +++ b/servo-tidy.toml @@ -56,6 +56,7 @@ files = [ "./components/net/tests/parsable_mime/text", # Mako does not lend itself easily to splitting long lines "./components/style/properties/helpers/animated_properties.mako.rs", + "./components/style/properties/shorthands/text.mako.rs", # Long regexes are long. "./components/style/gecko/regen_atoms.py", # Helper macro where actually a pseudo-element per line makes sense. diff --git a/tests/wpt/metadata/css/css-fonts/font-weight-xxx-large.html.ini b/tests/wpt/metadata/css/css-fonts/font-weight-xxx-large.html.ini deleted file mode 100644 index 86fcb0cf546a..000000000000 --- a/tests/wpt/metadata/css/css-fonts/font-weight-xxx-large.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[font-weight-xxx-large.html] - expected: FAIL diff --git a/tests/wpt/metadata/css/css-fonts/parsing/font-size-valid.html.ini b/tests/wpt/metadata/css/css-fonts/parsing/font-size-valid.html.ini deleted file mode 100644 index 4b1533148fc2..000000000000 --- a/tests/wpt/metadata/css/css-fonts/parsing/font-size-valid.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[font-size-valid.html] - [e.style['font-size'\] = "xxx-large" should set the property value] - expected: FAIL - diff --git a/tests/wpt/metadata/html/rendering/widgets/button-layout/display-other.html.ini b/tests/wpt/metadata/html/rendering/widgets/button-layout/display-other.html.ini index 95591d2929cb..e8cfab844933 100644 --- a/tests/wpt/metadata/html/rendering/widgets/button-layout/display-other.html.ini +++ b/tests/wpt/metadata/html/rendering/widgets/button-layout/display-other.html.ini @@ -44,9 +44,6 @@ [display: table-row-group] expected: FAIL - [display: flow] - expected: FAIL - [display: table-column-group] expected: FAIL