Auto merge of #23973 - emilio:gecko-sync, r=emilio,jdm

style: Sync changes from mozilla-central.

See each individual commit for details.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23973)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-08-16 06:44:52 -04:00 committed by GitHub
commit aa60077563
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 1040 additions and 1081 deletions

View file

@ -1847,6 +1847,10 @@ where
node.type_id() 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. // Switch on display and floatedness.
match (display, float, positioning) { match (display, float, positioning) {
// `display: none` contributes no flow construction result. // `display: none` contributes no flow construction result.
@ -1871,12 +1875,6 @@ where
self.set_flow_construction_result(node, construction_result) 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 // Inline items that are absolutely-positioned contribute inline fragment construction
// results with a hypothetical fragment. // results with a hypothetical fragment.
(Display::Inline, _, Position::Absolute) | (Display::Inline, _, Position::Absolute) |
@ -1958,7 +1956,12 @@ where
// properties separately. // properties separately.
(_, float_value, _) => { (_, float_value, _) => {
let float_kind = FloatKind::from_property(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) self.set_flow_construction_result(node, construction_result)
}, },
} }

View file

@ -19,7 +19,6 @@ use crate::traversal::InorderFlowTraversal;
use script_layout_interface::wrapper_traits::PseudoElementType; use script_layout_interface::wrapper_traits::PseudoElementType;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::collections::{HashMap, LinkedList}; 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::computed_values::list_style_type::T as ListStyleType;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::selector_parser::RestyleDamage; 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; 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 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) { fn reset_and_increment_counters_as_necessary(&mut self, fragment: &mut Fragment) {
let mut list_style_type = fragment.style().get_list().list_style_type; 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 list_style_type = ListStyleType::None
} }

View file

@ -414,16 +414,10 @@ impl Parse for Source {
macro_rules! is_descriptor_enabled { macro_rules! is_descriptor_enabled {
("font-display") => { ("font-display") => {
unsafe { static_prefs::pref!("layout.css.font-display.enabled")
use crate::gecko_bindings::structs::mozilla;
mozilla::StaticPrefs::sVarCache_layout_css_font_display_enabled
}
}; };
("font-variation-settings") => { ("font-variation-settings") => {
unsafe { static_prefs::pref!("layout.css.font-variations.enabled")
use crate::gecko_bindings::structs::mozilla;
mozilla::StaticPrefs::sVarCache_layout_css_font_variations_enabled != 0
}
}; };
($name:tt) => { ($name:tt) => {
true true

View file

@ -213,12 +213,11 @@ impl Device {
None => return MediaType::screen(), None => return MediaType::screen(),
}; };
// Gecko allows emulating random media with mIsEmulatingMedia and // Gecko allows emulating random media with mMediaEmulationData.mMedium.
// mMediaEmulated. let medium_to_use = if !pc.mMediaEmulationData.mMedium.mRawPtr.is_null() {
let medium_to_use = if pc.mIsEmulatingMedia() != 0 { pc.mMediaEmulationData.mMedium.mRawPtr
pc.mMediaEmulated.mRawPtr
} else { } else {
pc.mMedium pc.mMedium as *const structs::nsAtom as *mut _
}; };
MediaType(CustomIdent(unsafe { Atom::from_raw(medium_to_use) })) MediaType(CustomIdent(unsafe { Atom::from_raw(medium_to_use) }))
@ -253,9 +252,8 @@ impl Device {
None => return Scale::new(1.), None => return Scale::new(1.),
}; };
let override_dppx = pc.mOverrideDPPX; if pc.mMediaEmulationData.mDPPX > 0.0 {
if override_dppx > 0.0 { return Scale::new(pc.mMediaEmulationData.mDPPX);
return Scale::new(override_dppx);
} }
let au_per_dpx = pc.mCurAppUnitsPerDevPixel as f32; let au_per_dpx = pc.mCurAppUnitsPerDevPixel as f32;
@ -270,8 +268,7 @@ impl Device {
if doc.mIsBeingUsedAsImage() { if doc.mIsBeingUsedAsImage() {
return true; return true;
} }
let document_color_use = let document_color_use = static_prefs::pref!("browser.display.document_color_use");
unsafe { structs::StaticPrefs::sVarCache_browser_display_document_color_use };
let prefs = self.pref_sheet_prefs(); let prefs = self.pref_sheet_prefs();
match document_color_use { match document_color_use {
1 => true, 1 => true,

View file

@ -187,9 +187,7 @@ impl PseudoElement {
PseudoElement::FirstLine => PropertyFlags::APPLIES_TO_FIRST_LINE, PseudoElement::FirstLine => PropertyFlags::APPLIES_TO_FIRST_LINE,
PseudoElement::Placeholder => PropertyFlags::APPLIES_TO_PLACEHOLDER, PseudoElement::Placeholder => PropertyFlags::APPLIES_TO_PLACEHOLDER,
PseudoElement::Cue => PropertyFlags::APPLIES_TO_CUE, PseudoElement::Cue => PropertyFlags::APPLIES_TO_CUE,
PseudoElement::Marker PseudoElement::Marker if static_prefs::pref!("layout.css.marker.restricted") => {
if unsafe { structs::StaticPrefs::sVarCache_layout_css_marker_restricted } =>
{
PropertyFlags::APPLIES_TO_MARKER PropertyFlags::APPLIES_TO_MARKER
}, },
_ => return None, _ => return None,

View file

@ -112,7 +112,7 @@ impl PseudoElement {
% for pseudo in PSEUDOS: % for pseudo in PSEUDOS:
${pseudo_element_variant(pseudo)} => ${pseudo_element_variant(pseudo)} =>
% if pseudo.is_tree_pseudo_element(): % 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 0
} else { } else {
structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME 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-") { if starts_with_ignore_ascii_case(name, "-moz-tree-") {
return PseudoElement::tree_pseudo_element(name, Box::new([])) return PseudoElement::tree_pseudo_element(name, Box::new([]))
} }
if unsafe { if static_prefs::pref!("layout.css.unknown-webkit-pseudo-element") {
structs::StaticPrefs::sVarCache_layout_css_unknown_webkit_pseudo_element
} {
const WEBKIT_PREFIX: &str = "-webkit-"; const WEBKIT_PREFIX: &str = "-webkit-";
if starts_with_ignore_ascii_case(name, WEBKIT_PREFIX) { if starts_with_ignore_ascii_case(name, WEBKIT_PREFIX) {
let part = string_as_ascii_lowercase(&name[WEBKIT_PREFIX.len()..]); let part = string_as_ascii_lowercase(&name[WEBKIT_PREFIX.len()..]);

View file

@ -5,7 +5,7 @@
//! Gecko-specific bits for selector-parsing. //! Gecko-specific bits for selector-parsing.
use crate::element_state::{DocumentState, ElementState}; 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::gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
use crate::invalidation::element::document_state::InvalidationMatchingData; use crate::invalidation::element::document_state::InvalidationMatchingData;
use crate::selector_parser::{Direction, SelectorParser}; use crate::selector_parser::{Direction, SelectorParser};
@ -170,13 +170,10 @@ impl NonTSPseudoClass {
/// Returns whether the pseudo-class is enabled in content sheets. /// Returns whether the pseudo-class is enabled in content sheets.
fn is_enabled_in_content(&self) -> bool { fn is_enabled_in_content(&self) -> bool {
use crate::gecko_bindings::structs::mozilla;
match *self { match *self {
// For pseudo-classes with pref, the availability in content // For pseudo-classes with pref, the availability in content
// depends on the pref. // depends on the pref.
NonTSPseudoClass::Fullscreen => unsafe { NonTSPseudoClass::Fullscreen => static_prefs::pref!("full-screen-api.unprefix.enabled"),
mozilla::StaticPrefs::sVarCache_full_screen_api_unprefix_enabled
},
// Otherwise, a pseudo-class is enabled in content when it // Otherwise, a pseudo-class is enabled in content when it
// doesn't have any enabled flag. // doesn't have any enabled flag.
_ => !self _ => !self
@ -354,8 +351,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
#[inline] #[inline]
fn parse_part(&self) -> bool { fn parse_part(&self) -> bool {
self.chrome_rules_enabled() || self.chrome_rules_enabled() || static_prefs::pref!("layout.css.shadow-parts.enabled")
unsafe { structs::StaticPrefs::sVarCache_layout_css_shadow_parts_enabled }
} }
fn parse_non_ts_pseudo_class( fn parse_non_ts_pseudo_class(

View file

@ -91,6 +91,8 @@ extern crate servo_config;
extern crate servo_url; extern crate servo_url;
extern crate smallbitvec; extern crate smallbitvec;
extern crate smallvec; extern crate smallvec;
#[cfg(feature = "gecko")]
extern crate static_prefs;
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
extern crate string_cache; extern crate string_cache;
#[macro_use] #[macro_use]

View file

@ -11,8 +11,6 @@ use super::Device;
use crate::context::QuirksMode; use crate::context::QuirksMode;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::gecko::media_features::MEDIA_FEATURES; use crate::gecko::media_features::MEDIA_FEATURES;
#[cfg(feature = "gecko")]
use crate::gecko_bindings::structs;
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
use crate::servo::media_queries::MEDIA_FEATURES; use crate::servo::media_queries::MEDIA_FEATURES;
@ -301,9 +299,7 @@ impl MediaFeatureExpression {
if starts_with_ignore_ascii_case(feature_name, "-webkit-") { if starts_with_ignore_ascii_case(feature_name, "-webkit-") {
feature_name = &feature_name[8..]; feature_name = &feature_name[8..];
requirements.insert(ParsingRequirements::WEBKIT_PREFIX); requirements.insert(ParsingRequirements::WEBKIT_PREFIX);
if unsafe { if static_prefs::pref!("layout.css.prefixes.device-pixel-ratio-webkit") {
structs::StaticPrefs::sVarCache_layout_css_prefixes_device_pixel_ratio_webkit
} {
requirements.insert( requirements.insert(
ParsingRequirements::WEBKIT_DEVICE_PIXEL_RATIO_PREF_ENABLED, ParsingRequirements::WEBKIT_DEVICE_PIXEL_RATIO_PREF_ENABLED,
); );

View file

@ -673,7 +673,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
#[inline] #[inline]
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
fn recompute_default_font_family_type_if_needed(&mut self) { 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; use crate::values::computed::font::GenericFontFamily;
if !self.seen.contains(LonghandId::XLang) && if !self.seen.contains(LonghandId::XLang) &&
@ -681,7 +681,7 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
return; 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 builder = &mut self.context.builder;
let (default_font_type, prioritize_user_fonts) = { let (default_font_type, prioritize_user_fonts) = {
let font = builder.get_font().gecko(); let font = builder.get_font().gecko();

View file

@ -652,9 +652,6 @@ def _remove_common_first_line_and_first_letter_properties(props, engine):
props.remove("text-emphasis-position") props.remove("text-emphasis-position")
props.remove("text-emphasis-style") props.remove("text-emphasis-style")
props.remove("text-emphasis-color") 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("overflow-wrap")
props.remove("text-align") props.remove("text-align")

View file

@ -973,11 +973,10 @@ fn static_assert() {
<% skip_position_longhands = " ".join(x.ident for x in SIDES) %> <% skip_position_longhands = " ".join(x.ident for x in SIDES) %>
<%self:impl_trait style_struct_name="Position" <%self:impl_trait style_struct_name="Position"
skip_longhands="${skip_position_longhands} order skip_longhands="${skip_position_longhands}
align-content justify-content align-self align-content justify-content align-self
justify-self align-items justify-items justify-self align-items justify-items
grid-auto-flow grid-template-rows grid-auto-flow">
grid-template-columns">
% for side in SIDES: % for side in SIDES:
<% impl_split_style_coord(side.ident, "mOffset", side.index) %> <% impl_split_style_coord(side.ident, "mOffset", side.index) %>
% endfor % 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<structs::RefPtr<structs::nsAtom>>) {
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 <line-names>
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 <auto-track-repeat> 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 <auto-repeat>
// 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 <track-size> for <auto-track-repeat>")
} else {
match values_iter.next().expect("expected <track-size> 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<structs::RefPtr<structs::nsAtom>>) -> Box<[CustomIdent]> {
let idents: Vec<CustomIdent> = 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<nsTArray<structs::RefPtr<structs::nsAtom>>>,
) -> Vec<Box<[CustomIdent]>> {
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<Box<[CustomIdent]>> = 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")} ${impl_simple_type_with_conversion("grid_auto_flow")}
</%self:impl_trait> </%self:impl_trait>
@ -2799,97 +2578,15 @@ fn static_assert() {
<%self:impl_trait style_struct_name="InheritedText" <%self:impl_trait style_struct_name="InheritedText"
skip_longhands="text-align text-emphasis-style skip_longhands="text-align -webkit-text-stroke-width text-emphasis-position">
-webkit-text-stroke-width text-emphasis-position">
<% text_align_keyword = Keyword("text-align", <% text_align_keyword = Keyword("text-align",
"start end left right center justify -moz-center -moz-left -moz-right char", "start end left right center justify -moz-center -moz-left -moz-right char",
gecko_strip_moz_prefix=False) %> gecko_strip_moz_prefix=False) %>
${impl_keyword('text_align', 'mTextAlign', text_align_keyword)} ${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")} ${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', ${impl_non_negative_length('_webkit_text_stroke_width',
'mWebkitTextStrokeWidth')} 'mWebkitTextStrokeWidth')}

View file

@ -58,7 +58,6 @@
animation_value_type="NonNegativeLength", animation_value_type="NonNegativeLength",
logical=is_logical, logical=is_logical,
logical_group="border-width", logical_group="border-width",
flags="GETCS_NEEDS_LAYOUT_FLUSH",
allow_quirks="No" if is_logical else "Yes", allow_quirks="No" if is_logical else "Yes",
servo_restyle_damage="reflow rebuild_and_reflow_inline" servo_restyle_damage="reflow rebuild_and_reflow_inline"
)} )}

View file

@ -339,8 +339,7 @@ ${helpers.predefined_type(
servo_2020_pref="layout.2020.unimplemented", servo_2020_pref="layout.2020.unimplemented",
extra_prefixes=transform_extra_prefixes, extra_prefixes=transform_extra_prefixes,
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB \ flags="CREATES_STACKING_CONTEXT FIXPOS_CB CAN_ANIMATE_ON_COMPOSITOR",
GETCS_NEEDS_LAYOUT_FLUSH CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.csswg.org/css-transforms/#propdef-transform", spec="https://drafts.csswg.org/css-transforms/#propdef-transform",
servo_restyle_damage="reflow_out_of_flow", servo_restyle_damage="reflow_out_of_flow",
)} )}
@ -421,6 +420,19 @@ ${helpers.predefined_type(
servo_restyle_damage="reflow_out_of_flow" 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 // CSSOM View Module
// https://www.w3.org/TR/cssom-view-1/ // https://www.w3.org/TR/cssom-view-1/
${helpers.single_keyword( ${helpers.single_keyword(
@ -539,7 +551,6 @@ ${helpers.predefined_type(
boxed=True, boxed=True,
extra_prefixes=transform_extra_prefixes, extra_prefixes=transform_extra_prefixes,
spec="https://drafts.csswg.org/css-transforms-2/#perspective-origin-property", spec="https://drafts.csswg.org/css-transforms-2/#perspective-origin-property",
flags="GETCS_NEEDS_LAYOUT_FLUSH",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
servo_restyle_damage="reflow_out_of_flow" servo_restyle_damage="reflow_out_of_flow"
)} )}
@ -587,7 +598,6 @@ ${helpers.predefined_type(
extra_prefixes=transform_extra_prefixes, extra_prefixes=transform_extra_prefixes,
gecko_ffi_name="mTransformOrigin", gecko_ffi_name="mTransformOrigin",
boxed=True, boxed=True,
flags="GETCS_NEEDS_LAYOUT_FLUSH",
spec="https://drafts.csswg.org/css-transforms/#transform-origin-property", spec="https://drafts.csswg.org/css-transforms/#transform-origin-property",
servo_restyle_damage="reflow_out_of_flow", servo_restyle_damage="reflow_out_of_flow",
)} )}

View file

@ -23,7 +23,6 @@ ${helpers.predefined_type(
engines="gecko servo-2013 servo-2020", engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented", servo_2020_pref="layout.2020.unimplemented",
animation_value_type="LineHeight", animation_value_type="LineHeight",
flags="GETCS_NEEDS_LAYOUT_FLUSH",
spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height", spec="https://drafts.csswg.org/css2/visudet.html#propdef-line-height",
servo_restyle_damage="reflow" servo_restyle_damage="reflow"
)} )}
@ -250,7 +249,6 @@ ${helpers.predefined_type(
None, None,
engines="gecko", engines="gecko",
initial_specified_value="SpecifiedValue::None", initial_specified_value="SpecifiedValue::None",
boxed=True,
animation_value_type="discrete", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-style", spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-style",
)} )}
@ -384,8 +382,8 @@ ${helpers.single_keyword(
// text underline offset // text underline offset
${helpers.predefined_type( ${helpers.predefined_type(
"text-underline-offset", "text-underline-offset",
"LengthOrAuto", "TextDecorationLength",
"computed::LengthOrAuto::auto()", "generics::text::GenericTextDecorationLength::Auto",
engines="gecko", engines="gecko",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
gecko_pref="layout.css.text-underline-offset.enabled", gecko_pref="layout.css.text-underline-offset.enabled",

View file

@ -24,7 +24,6 @@
logical=side[1], logical=side[1],
logical_group="margin", logical_group="margin",
spec=spec, spec=spec,
flags="GETCS_NEEDS_LAYOUT_FLUSH",
allowed_in_page_rule=True, allowed_in_page_rule=True,
servo_restyle_damage="reflow" servo_restyle_damage="reflow"
)} )}

View file

@ -23,7 +23,6 @@
logical=side[1], logical=side[1],
logical_group="padding", logical_group="padding",
spec=spec, spec=spec,
flags="GETCS_NEEDS_LAYOUT_FLUSH",
allow_quirks="No" if side[1] else "Yes", allow_quirks="No" if side[1] else "Yes",
servo_restyle_damage="reflow rebuild_and_reflow_inline" servo_restyle_damage="reflow rebuild_and_reflow_inline"
)} )}

View file

@ -17,7 +17,6 @@
engines="gecko servo-2013 servo-2020", engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented", servo_2020_pref="layout.2020.unimplemented",
spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side, spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side,
flags="GETCS_NEEDS_LAYOUT_FLUSH",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
allow_quirks="Yes", allow_quirks="Yes",
servo_restyle_damage="reflow_out_of_flow", servo_restyle_damage="reflow_out_of_flow",
@ -33,7 +32,6 @@
engines="gecko servo-2013 servo-2020", engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented", servo_2020_pref="layout.2020.unimplemented",
spec="https://drafts.csswg.org/css-logical-props/#propdef-inset-%s" % side, 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, alias="offset-%s:layout.css.offset-logical-properties.enabled" % side,
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
logical=True, logical=True,
@ -285,7 +283,6 @@ ${helpers.predefined_type(
allow_quirks="No" if logical else "Yes", allow_quirks="No" if logical else "Yes",
spec=spec % size, spec=spec % size,
animation_value_type="Size", animation_value_type="Size",
flags="GETCS_NEEDS_LAYOUT_FLUSH",
servo_restyle_damage="reflow", servo_restyle_damage="reflow",
)} )}
// min-width, min-height, min-block-size, min-inline-size // min-width, min-height, min-block-size, min-inline-size
@ -360,16 +357,13 @@ ${helpers.predefined_type(
)} )}
% endfor % endfor
// NOTE: According to the spec, this should handle multiple values of `<track-size>`,
// but gecko supports only a single value
${helpers.predefined_type( ${helpers.predefined_type(
"grid-auto-%ss" % kind, "grid-auto-%ss" % kind,
"TrackSize", "ImplicitGridTracks",
"Default::default()", "Default::default()",
engines="gecko", engines="gecko",
animation_value_type="discrete", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind, spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind,
boxed=True,
)} )}
${helpers.predefined_type( ${helpers.predefined_type(
@ -378,8 +372,6 @@ ${helpers.predefined_type(
"specified::GenericGridTemplateComponent::None", "specified::GenericGridTemplateComponent::None",
engines="gecko", engines="gecko",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-%ss" % kind, spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-%ss" % kind,
boxed=True,
flags="GETCS_NEEDS_LAYOUT_FLUSH",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
)} )}

View file

@ -71,9 +71,10 @@ ${helpers.predefined_type(
${helpers.predefined_type( ${helpers.predefined_type(
"text-decoration-thickness", "text-decoration-thickness",
"LengthOrAuto", "TextDecorationLength",
"computed::LengthOrAuto::auto()", "generics::text::GenericTextDecorationLength::Auto",
engines="gecko", engines="gecko",
initial_specified_value="generics::text::GenericTextDecorationLength::Auto",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
gecko_pref="layout.css.text-decoration-thickness.enabled", gecko_pref="layout.css.text-decoration-thickness.enabled",
spec="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property" spec="https://drafts.csswg.org/css-text-decor-4/#text-decoration-width-property"

View file

@ -80,7 +80,6 @@ ${helpers.predefined_type(
"Transform", "Transform",
"generics::transform::Transform::none()", "generics::transform::Transform::none()",
engines="gecko", engines="gecko",
flags="GETCS_NEEDS_LAYOUT_FLUSH",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
spec="None (Nonstandard internal property)", spec="None (Nonstandard internal property)",
enabled_in="chrome", enabled_in="chrome",
@ -94,7 +93,6 @@ ${helpers.predefined_type(
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
gecko_ffi_name="mWindowTransformOrigin", gecko_ffi_name="mWindowTransformOrigin",
boxed=True, boxed=True,
flags="GETCS_NEEDS_LAYOUT_FLUSH",
spec="None (Nonstandard internal property)", spec="None (Nonstandard internal property)",
enabled_in="chrome", enabled_in="chrome",
)} )}

View file

@ -981,13 +981,10 @@ bitflags! {
const APPLIES_TO_CUE = 1 << 6; const APPLIES_TO_CUE = 1 << 6;
/// This longhand property applies to ::marker. /// This longhand property applies to ::marker.
const APPLIES_TO_MARKER = 1 << 7; 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. /// This property is a legacy shorthand.
/// ///
/// https://drafts.csswg.org/css-cascade/#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 /* The following flags are currently not used in Rust code, they
* only need to be listed in corresponding properties so that * only need to be listed in corresponding properties so that

View file

@ -268,7 +268,7 @@
> >
use crate::parser::Parse; use crate::parser::Parse;
use servo_arc::Arc; 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::generics::grid::{TrackListValue, concat_serialize_idents};
use crate::values::specified::{GridTemplateComponent, GenericGridTemplateComponent}; use crate::values::specified::{GridTemplateComponent, GenericGridTemplateComponent};
use crate::values::specified::grid::parse_line_names; use crate::values::specified::grid::parse_line_names;
@ -300,26 +300,28 @@
} }
% endfor % 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())) { 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 strings = vec![];
let mut values = vec![]; let mut values = vec![];
let mut line_names = vec![]; let mut line_names = vec![];
let mut names = first_line_names.into_vec(); let mut names = first_line_names;
loop { loop {
line_names.push(names.into_boxed_slice()); line_names.push(names);
strings.push(string); strings.push(string);
let size = input.try(|i| TrackSize::parse(context, i)).unwrap_or_default(); let size = input.try(|i| TrackSize::parse(context, i)).unwrap_or_default();
values.push(TrackListValue::TrackSize(size)); 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) { 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())) { string = match input.try(|i| i.expect_string().map(|s| s.as_ref().to_owned().into())) {
Ok(s) => s, Ok(s) => s,
_ => { // only the named area determines whether we should bail out _ => { // only the named area determines whether we should bail out
line_names.push(names.into_boxed_slice()); line_names.push(names.into());
break break
}, },
}; };
@ -327,22 +329,21 @@
if line_names.len() == values.len() { if line_names.len() == values.len() {
// should be one longer than track sizes // 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) let template_areas = TemplateAreas::from_vec(strings)
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))?; .map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))?;
let template_rows = TrackList { let template_rows = TrackList {
list_type: TrackListType::Normal, values: values.into(),
values, line_names: line_names.into(),
line_names: line_names.into_boxed_slice(), auto_repeat_index: std::usize::MAX,
auto_repeat: None,
}; };
let template_cols = if input.try(|i| i.expect_delim('/')).is_ok() { let template_cols = if input.try(|i| i.expect_delim('/')).is_ok() {
let value = GridTemplateComponent::parse_without_none(context, input)?; let value = GridTemplateComponent::parse_without_none(context, input)?;
if let GenericGridTemplateComponent::TrackList(ref list) = value { 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)) return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
} }
} }
@ -352,8 +353,11 @@
GenericGridTemplateComponent::None GenericGridTemplateComponent::None
}; };
Ok((GenericGridTemplateComponent::TrackList(template_rows), Ok((
template_cols, GridTemplateAreas::Areas(TemplateAreasArc(Arc::new(template_areas))))) GenericGridTemplateComponent::TrackList(Box::new(template_rows)),
template_cols,
GridTemplateAreas::Areas(TemplateAreasArc(Arc::new(template_areas)))
))
} else { } else {
let mut template_rows = GridTemplateComponent::parse(context, input)?; let mut template_rows = GridTemplateComponent::parse(context, input)?;
if let GenericGridTemplateComponent::TrackList(ref mut list) = template_rows { if let GenericGridTemplateComponent::TrackList(ref mut list) = template_rows {
@ -407,13 +411,10 @@
let track_list = match *template_rows { let track_list = match *template_rows {
GenericGridTemplateComponent::TrackList(ref list) => { GenericGridTemplateComponent::TrackList(ref list) => {
// We should fail if there is a `repeat` function. `grid` and // We should fail if there is a `repeat` function.
// `grid-template` shorthands doesn't accept that. Only longhand accepts. // `grid` and `grid-template` shorthands doesn't accept
if list.auto_repeat.is_some() || // that. Only longhand accepts.
list.values.iter().any(|v| match *v { if !list.is_explicit() {
TrackListValue::TrackRepeat(_) => true,
_ => false,
}) {
return Ok(()); return Ok(());
} }
list list
@ -429,11 +430,7 @@
// We should fail if there is a `repeat` function. `grid` and // We should fail if there is a `repeat` function. `grid` and
// `grid-template` shorthands doesn't accept that. Only longhand accepts that. // `grid-template` shorthands doesn't accept that. Only longhand accepts that.
GenericGridTemplateComponent::TrackList(ref list) => { GenericGridTemplateComponent::TrackList(ref list) => {
if list.auto_repeat.is_some() || if !list.is_explicit() {
list.values.iter().any(|v| match *v {
TrackListValue::TrackRepeat(_) => true,
_ => false,
}) {
return Ok(()); return Ok(());
} }
}, },
@ -498,8 +495,8 @@
> >
use crate::parser::Parse; use crate::parser::Parse;
use crate::properties::longhands::{grid_auto_columns, grid_auto_rows, grid_auto_flow}; use crate::properties::longhands::{grid_auto_columns, grid_auto_rows, grid_auto_flow};
use crate::values::generics::grid::{GridTemplateComponent, TrackListType}; use crate::values::generics::grid::GridTemplateComponent;
use crate::values::specified::{GenericGridTemplateComponent, TrackSize}; use crate::values::specified::{GenericGridTemplateComponent, ImplicitGridTracks};
use crate::values::specified::position::{AutoFlow, GridAutoFlow, GridTemplateAreas}; use crate::values::specified::position::{AutoFlow, GridAutoFlow, GridTemplateAreas};
pub fn parse_value<'i, 't>( pub fn parse_value<'i, 't>(
@ -509,8 +506,8 @@
let mut temp_rows = GridTemplateComponent::None; let mut temp_rows = GridTemplateComponent::None;
let mut temp_cols = GridTemplateComponent::None; let mut temp_cols = GridTemplateComponent::None;
let mut temp_areas = GridTemplateAreas::None; let mut temp_areas = GridTemplateAreas::None;
let mut auto_rows = TrackSize::default(); let mut auto_rows = ImplicitGridTracks::default();
let mut auto_cols = TrackSize::default(); let mut auto_cols = ImplicitGridTracks::default();
let mut flow = grid_auto_flow::get_initial_value(); let mut flow = grid_auto_flow::get_initial_value();
fn parse_auto_flow<'i, 't>( fn parse_auto_flow<'i, 't>(
@ -571,8 +568,8 @@
/// Returns true if other sub properties except template-{rows,columns} are initial. /// Returns true if other sub properties except template-{rows,columns} are initial.
fn is_grid_template(&self) -> bool { fn is_grid_template(&self) -> bool {
*self.grid_template_areas == GridTemplateAreas::None && *self.grid_template_areas == GridTemplateAreas::None &&
*self.grid_auto_rows == TrackSize::default() && self.grid_auto_rows.is_initial() &&
*self.grid_auto_columns == TrackSize::default() && self.grid_auto_columns.is_initial() &&
*self.grid_auto_flow == grid_auto_flow::get_initial_value() *self.grid_auto_flow == grid_auto_flow::get_initial_value()
} }
} }
@ -590,14 +587,14 @@
if self.grid_auto_flow.autoflow == AutoFlow::Column { if self.grid_auto_flow.autoflow == AutoFlow::Column {
// It should fail to serialize if other branch of the if condition's values are set. // 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 { *self.grid_template_columns != GridTemplateComponent::None {
return Ok(()); return Ok(());
} }
// It should fail to serialize if template-rows value is not Explicit. // It should fail to serialize if template-rows value is not Explicit.
if let GenericGridTemplateComponent::TrackList(ref list) = *self.grid_template_rows { if let GenericGridTemplateComponent::TrackList(ref list) = *self.grid_template_rows {
if list.list_type != TrackListType::Explicit { if !list.is_explicit() {
return Ok(()); return Ok(());
} }
} }
@ -608,20 +605,20 @@
dest.write_str(" dense")?; dest.write_str(" dense")?;
} }
if !self.grid_auto_columns.is_default() { if !self.grid_auto_columns.is_initial() {
dest.write_str(" ")?; dest.write_str(" ")?;
self.grid_auto_columns.to_css(dest)?; self.grid_auto_columns.to_css(dest)?;
} }
} else { } else {
// It should fail to serialize if other branch of the if condition's values are set. // 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 { *self.grid_template_rows != GridTemplateComponent::None {
return Ok(()); return Ok(());
} }
// It should fail to serialize if template-column value is not Explicit. // It should fail to serialize if template-column value is not Explicit.
if let GenericGridTemplateComponent::TrackList(ref list) = *self.grid_template_columns { if let GenericGridTemplateComponent::TrackList(ref list) = *self.grid_template_columns {
if list.list_type != TrackListType::Explicit { if !list.is_explicit() {
return Ok(()); return Ok(());
} }
} }
@ -631,7 +628,7 @@
dest.write_str(" dense")?; dest.write_str(" dense")?;
} }
if !self.grid_auto_rows.is_default() { if !self.grid_auto_rows.is_initial() {
dest.write_str(" ")?; dest.write_str(" ")?;
self.grid_auto_rows.to_css(dest)?; self.grid_auto_rows.to_css(dest)?;
} }

View file

@ -8,12 +8,13 @@
engines="gecko servo-2013" engines="gecko servo-2013"
flags="SHORTHAND_IN_GETCS" flags="SHORTHAND_IN_GETCS"
sub_properties="text-decoration-line 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"> spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration">
% if engine == "gecko": % if engine == "gecko":
use crate::values::specified; 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 % endif
use crate::properties::longhands::text_decoration_line; use crate::properties::longhands::text_decoration_line;
@ -22,7 +23,10 @@
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Longhands, ParseError<'i>> { ) -> Result<Longhands, ParseError<'i>> {
% if engine == "gecko": % 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: % else:
let (mut line, mut any) = (None, false); let (mut line, mut any) = (None, false);
% endif % endif
@ -45,6 +49,9 @@
% if engine == "gecko": % if engine == "gecko":
parse_component!(style, text_decoration_style); parse_component!(style, text_decoration_style);
parse_component!(color, text_decoration_color); parse_component!(color, text_decoration_color);
if text_decoration_thickness_enabled {
parse_component!(thickness, text_decoration_thickness);
}
% endif % endif
break; break;
@ -60,6 +67,7 @@
% if engine == "gecko": % if engine == "gecko":
text_decoration_style: unwrap_or_initial!(text_decoration_style, style), text_decoration_style: unwrap_or_initial!(text_decoration_style, style),
text_decoration_color: unwrap_or_initial!(text_decoration_color, color), text_decoration_color: unwrap_or_initial!(text_decoration_color, color),
text_decoration_thickness: unwrap_or_initial!(text_decoration_thickness, thickness),
% endif % endif
}) })
} }
@ -78,6 +86,13 @@
dest.write_str(" ")?; dest.write_str(" ")?;
self.text_decoration_color.to_css(dest)?; 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 % endif
Ok(()) Ok(())

View file

@ -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::overflow_x::computed_value::T as Overflow;
use crate::properties::longhands::position::computed_value::T as Position; use crate::properties::longhands::position::computed_value::T as Position;
use crate::properties::{self, ComputedValues, StyleBuilder}; use crate::properties::{self, ComputedValues, StyleBuilder};
use crate::values::specified::box_::DisplayInside;
use app_units::Au; use app_units::Au;
/// A struct that implements all the adjustment methods. /// 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. /// Apply the blockification rules based on the table in CSS 2.2 section 9.7.
/// <https://drafts.csswg.org/css2/visuren.html#dis-pos-flo> /// <https://drafts.csswg.org/css2/visuren.html#dis-pos-flo>
/// A ::marker pseudo-element with 'list-style-position:outside' needs to /// 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<E>(&mut self, layout_parent_style: &ComputedValues, element: Option<E>) fn blockify_if_necessary<E>(&mut self, layout_parent_style: &ComputedValues, element: Option<E>)
where where
E: TElement, 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()); let is_root = self.style.pseudo.is_none() && element.map_or(false, |e| e.is_root());
blockify_if!(is_root); blockify_if!(is_root);
if !self.skip_item_display_fixup(element) { if !self.skip_item_display_fixup(element) {
blockify_if!(layout_parent_style let parent_display = layout_parent_style.get_box().clone_display();
.get_box() blockify_if!(parent_display.is_item_container());
.clone_display()
.is_item_container());
} }
let is_item_or_root = blockify; let is_item_or_root = blockify;
@ -207,7 +208,8 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
blockify_if!( blockify_if!(
self.style.pseudo.map_or(false, |p| p.is_marker()) && self.style.pseudo.map_or(false, |p| p.is_marker()) &&
self.style.get_parent_list().clone_list_style_position() == 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 { if !blockify {

View file

@ -253,20 +253,18 @@ impl DocumentCondition {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
fn allowed_in(&self, context: &ParserContext) -> bool { fn allowed_in(&self, context: &ParserContext) -> bool {
use crate::gecko_bindings::structs;
use crate::stylesheets::Origin; use crate::stylesheets::Origin;
use static_prefs::pref;
if context.stylesheet_origin != Origin::Author { if context.stylesheet_origin != Origin::Author {
return true; return true;
} }
if unsafe { structs::StaticPrefs::sVarCache_layout_css_moz_document_content_enabled } { if pref!("layout.css.moz-document.content.enabled") {
return true; return true;
} }
if !unsafe { if !pref!("layout.css.moz-document.url-prefix-hack.enabled") {
structs::StaticPrefs::sVarCache_layout_css_moz_document_url_prefix_hack_enabled
} {
return false; return false;
} }

View file

@ -323,9 +323,7 @@ impl RawSelector {
pub fn eval(&self, context: &ParserContext, namespaces: &Namespaces) -> bool { pub fn eval(&self, context: &ParserContext, namespaces: &Namespaces) -> bool {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
{ {
if unsafe { if !static_prefs::pref!("layout.css.supports-selector.enabled") {
!crate::gecko_bindings::structs::StaticPrefs::sVarCache_layout_css_supports_selector_enabled
} {
return false; return false;
} }
} }

View file

@ -101,7 +101,7 @@ impl Animate for generics::TrackRepeat<LengthPercentage, Integer> {
Ok(generics::TrackRepeat { Ok(generics::TrackRepeat {
count, count,
line_names, line_names,
track_sizes, track_sizes: track_sizes.into(),
}) })
} }
} }
@ -117,20 +117,19 @@ impl Animate for TrackList {
return Err(()); return Err(());
} }
if self.list_type != other.list_type { if self.is_explicit() != other.is_explicit() {
return Err(()); return Err(());
} }
// For now, repeat(auto-fill/auto-fit, ...) is not animatable. TrackRepeat will // For now, repeat(auto-fill/auto-fit, ...) is not animatable.
// return Err(()) if we use keywords. Therefore, we can early return here to avoid // TrackRepeat will return Err(()) if we use keywords. Therefore, we can
// traversing |values| in <auto-track-list>. This may be updated in the future. // early return here to avoid traversing |values| in <auto-track-list>.
// This may be updated in the future.
// https://github.com/w3c/csswg-drafts/issues/3503 // 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(()); return Err(());
} }
let list_type = self.list_type;
let auto_repeat = self.auto_repeat.animate(&other.auto_repeat, procedure)?;
let values = self let values = self
.values .values
.iter() .iter()
@ -142,10 +141,9 @@ impl Animate for TrackList {
let line_names = discrete(&self.line_names, &other.line_names, procedure)?; let line_names = discrete(&self.line_names, &other.line_names, procedure)?;
Ok(TrackList { Ok(TrackList {
list_type, values: values.into(),
values,
line_names, line_names,
auto_repeat, auto_repeat_index: self.auto_repeat_index,
}) })
} }
} }

View file

@ -7,6 +7,7 @@
use self::transform::DirectionVector; use self::transform::DirectionVector;
use super::animated::ToAnimatedValue; use super::animated::ToAnimatedValue;
use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
use super::generics::grid::ImplicitGridTracks as GenericImplicitGridTracks;
use super::generics::grid::{GenericGridLine, GenericTrackBreadth}; use super::generics::grid::{GenericGridLine, GenericTrackBreadth};
use super::generics::grid::{GenericTrackSize, TrackList as GenericTrackList}; use super::generics::grid::{GenericTrackSize, TrackList as GenericTrackList};
use super::generics::transform::IsParallelTo; use super::generics::transform::IsParallelTo;
@ -68,17 +69,17 @@ pub use self::list::Quotes;
pub use self::motion::{OffsetPath, OffsetRotate}; pub use self::motion::{OffsetPath, OffsetRotate};
pub use self::outline::OutlineStyle; pub use self::outline::OutlineStyle;
pub use self::percentage::{NonNegativePercentage, Percentage}; 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::rect::NonNegativeLengthOrNumberRect;
pub use self::resolution::Resolution; pub use self::resolution::Resolution;
pub use self::svg::MozContextProperties; pub use self::svg::MozContextProperties;
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::table::XSpan; pub use self::table::XSpan;
pub use self::text::TextDecorationSkipInk;
pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight}; pub use self::text::{InitialLetter, LetterSpacing, LineBreak, LineHeight};
pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing}; pub use self::text::{OverflowWrap, TextOverflow, WordBreak, WordSpacing};
pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle}; pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle};
pub use self::text::{TextDecorationLength, TextDecorationSkipInk};
pub use self::time::Time; pub use self::time::Time;
pub use self::transform::{Rotate, Scale, Transform, TransformOperation}; pub use self::transform::{Rotate, Scale, Transform, TransformOperation};
pub use self::transform::{TransformOrigin, TransformStyle, Translate}; 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!(u8);
trivial_to_computed_value!(u16); trivial_to_computed_value!(u16);
trivial_to_computed_value!(u32); trivial_to_computed_value!(u32);
trivial_to_computed_value!(usize);
trivial_to_computed_value!(Atom); trivial_to_computed_value!(Atom);
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
trivial_to_computed_value!(Prefix); trivial_to_computed_value!(Prefix);
@ -695,6 +697,9 @@ pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>;
/// The computed value of a grid `<track-size>` /// The computed value of a grid `<track-size>`
pub type TrackSize = GenericTrackSize<LengthPercentage>; pub type TrackSize = GenericTrackSize<LengthPercentage>;
/// The computed value of a grid `<track-size>+`
pub type ImplicitGridTracks = GenericImplicitGridTracks<TrackSize>;
/// The computed value of a grid `<track-list>` /// The computed value of a grid `<track-list>`
/// (could also be `<auto-track-list>` or `<explicit-track-list>`) /// (could also be `<auto-track-list>` or `<explicit-track-list>`)
pub type TrackList = GenericTrackList<LengthPercentage, Integer>; pub type TrackList = GenericTrackList<LengthPercentage, Integer>;

View file

@ -9,6 +9,7 @@
use crate::values::computed::{Integer, LengthPercentage, Percentage}; use crate::values::computed::{Integer, LengthPercentage, Percentage};
use crate::values::generics::position::Position as GenericPosition; 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::generics::position::ZIndex as GenericZIndex;
pub use crate::values::specified::position::{GridAutoFlow, GridTemplateAreas}; pub use crate::values::specified::position::{GridAutoFlow, GridTemplateAreas};
use crate::Zero; use crate::Zero;
@ -18,6 +19,9 @@ use style_traits::{CssWriter, ToCss};
/// The computed value of a CSS `<position>` /// The computed value of a CSS `<position>`
pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>; pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>;
/// The computed value of an `auto | <position>`
pub type PositionOrAuto = GenericPositionOrAuto<Position>;
/// The computed value of a CSS horizontal position. /// The computed value of a CSS horizontal position.
pub type HorizontalPosition = LengthPercentage; pub type HorizontalPosition = LengthPercentage;

View file

@ -10,7 +10,7 @@ use crate::values::computed::length::{Length, LengthPercentage};
use crate::values::computed::{Context, NonNegativeLength, NonNegativeNumber, ToComputedValue}; use crate::values::computed::{Context, NonNegativeLength, NonNegativeNumber, ToComputedValue};
use crate::values::generics::text::InitialLetter as GenericInitialLetter; use crate::values::generics::text::InitialLetter as GenericInitialLetter;
use crate::values::generics::text::LineHeight as GenericLineHeight; 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::{self as specified, TextOverflowSide};
use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword}; use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword};
use crate::values::{CSSFloat, CSSInteger}; use crate::values::{CSSFloat, CSSInteger};
@ -26,6 +26,9 @@ pub use crate::values::specified::{TextDecorationSkipInk, TextTransform};
/// A computed value for the `initial-letter` property. /// A computed value for the `initial-letter` property.
pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>; pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
/// Implements type for `text-underline-offset` and `text-decoration-thickness` properties
pub type TextDecorationLength = GenericTextDecorationLength<Length>;
/// A computed value for the `letter-spacing` property. /// A computed value for the `letter-spacing` property.
#[repr(transparent)] #[repr(transparent)]
#[derive( #[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)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)]
#[allow(missing_docs)]
#[repr(C, u8)]
pub enum TextEmphasisStyle { pub enum TextEmphasisStyle {
/// Keyword value for the text-emphasis-style property (`filled` `open`) /// [ <fill> || <shape> ]
Keyword(TextEmphasisKeywordValue), Keyword {
#[css(skip_if = "TextEmphasisFillMode::is_filled")]
fill: TextEmphasisFillMode,
shape: TextEmphasisShapeKeyword,
},
/// `none` /// `none`
None, None,
/// String (will be used only first grapheme cluster) for the text-emphasis-style property /// `<string>` (of which only the first grapheme cluster will be used).
String(String), String(crate::OwnedStr),
}
/// 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,
} }

View file

@ -69,8 +69,7 @@ pub enum TimingKeyword {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
fn step_position_jump_enabled(_context: &ParserContext) -> bool { fn step_position_jump_enabled(_context: &ParserContext) -> bool {
use crate::gecko_bindings::structs; static_prefs::pref!("layout.css.step-position-jump.enabled")
unsafe { structs::StaticPrefs::sVarCache_layout_css_step_position_jump_enabled }
} }
#[cfg(feature = "servo")] #[cfg(feature = "servo")]

View file

@ -253,9 +253,7 @@ pub enum KeywordSize {
XLarge, XLarge,
#[css(keyword = "xx-large")] #[css(keyword = "xx-large")]
XXLarge, XXLarge,
// This is not a real font keyword and will not parse #[css(keyword = "xxx-large")]
// HTML font-size 7 corresponds to this value
#[css(skip)]
XXXLarge, XXXLarge,
} }

View file

@ -12,7 +12,7 @@ use crate::values::{CSSFloat, CustomIdent};
use crate::{Atom, Zero}; use crate::{Atom, Zero};
use cssparser::Parser; use cssparser::Parser;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::{cmp, mem, usize}; use std::{cmp, usize};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
/// These are the limits that we choose to clamp grid line numbers to. /// These are the limits that we choose to clamp grid line numbers to.
@ -290,16 +290,17 @@ impl<L> TrackSize<L> {
} }
} }
impl<L> Default for TrackSize<L> { impl<L: PartialEq> TrackSize<L> {
fn default() -> Self { /// Return true if it is `auto`.
TrackSize::Breadth(TrackBreadth::Auto) #[inline]
pub fn is_auto(&self) -> bool {
*self == TrackSize::Breadth(TrackBreadth::Auto)
} }
} }
impl<L: PartialEq> TrackSize<L> { impl<L> Default for TrackSize<L> {
/// Returns true if current TrackSize is same as default. fn default() -> Self {
pub fn is_default(&self) -> bool { TrackSize::Breadth(TrackBreadth::Auto)
*self == TrackSize::default()
} }
} }
@ -334,6 +335,39 @@ impl<L: ToCss> ToCss for TrackSize<L> {
} }
} }
/// A `<track-size>+`.
/// 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<T>(
#[css(if_empty = "auto", iterable)] pub crate::OwnedSlice<T>,
);
pub use self::GenericImplicitGridTracks as ImplicitGridTracks;
impl<T: fmt::Debug + Default + PartialEq> ImplicitGridTracks<T> {
/// 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 /// Helper function for serializing identifiers with a prefix and suffix, used
/// for serializing <line-names> (in grid). /// for serializing <line-names> (in grid).
pub fn concat_serialize_idents<W>( pub fn concat_serialize_idents<W>(
@ -366,6 +400,7 @@ where
#[derive( #[derive(
Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
)] )]
#[repr(C, u8)]
pub enum RepeatCount<Integer> { pub enum RepeatCount<Integer> {
/// A positive integer. This is allowed only for `<track-repeat>` and `<fixed-repeat>` /// A positive integer. This is allowed only for `<track-repeat>` and `<fixed-repeat>`
Number(Integer), Number(Integer),
@ -380,21 +415,18 @@ impl Parse for RepeatCount<specified::Integer> {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
// 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 let Ok(mut i) = input.try(|i| specified::Integer::parse_positive(context, i)) {
if i.value() > MAX_LINE { if i.value() > MAX_GRID_LINE {
i = specified::Integer::new(MAX_LINE); i = specified::Integer::new(MAX_GRID_LINE);
}
return Ok(RepeatCount::Number(i));
} }
Ok(RepeatCount::Number(i))
} else {
try_match_ident_ignore_ascii_case! { input, try_match_ident_ignore_ascii_case! { input,
"auto-fill" => Ok(RepeatCount::AutoFill), "auto-fill" => Ok(RepeatCount::AutoFill),
"auto-fit" => Ok(RepeatCount::AutoFit), "auto-fit" => Ok(RepeatCount::AutoFit),
} }
} }
} }
}
/// The structure containing `<line-names>` and `<track-size>` values. /// The structure containing `<line-names>` and `<track-size>` values.
/// ///
@ -411,7 +443,8 @@ impl Parse for RepeatCount<specified::Integer> {
ToShmem, ToShmem,
)] )]
#[css(function = "repeat")] #[css(function = "repeat")]
pub struct TrackRepeat<L, I> { #[repr(C)]
pub struct GenericTrackRepeat<L, I> {
/// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`) /// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`)
pub count: RepeatCount<I>, pub count: RepeatCount<I>,
/// `<line-names>` accompanying `<track_size>` values. /// `<line-names>` accompanying `<track_size>` values.
@ -419,11 +452,13 @@ pub struct TrackRepeat<L, I> {
/// If there's no `<line-names>`, then it's represented by an empty vector. /// If there's no `<line-names>`, then it's represented by an empty vector.
/// For N `<track-size>` values, there will be N+1 `<line-names>`, and so this vector's /// For N `<track-size>` values, there will be N+1 `<line-names>`, and so this vector's
/// length is always one value more than that of the `<track-size>`. /// length is always one value more than that of the `<track-size>`.
pub line_names: Box<[Box<[CustomIdent]>]>, pub line_names: crate::OwnedSlice<crate::OwnedSlice<CustomIdent>>,
/// `<track-size>` values. /// `<track-size>` values.
pub track_sizes: Vec<TrackSize<L>>, pub track_sizes: crate::OwnedSlice<GenericTrackSize<L>>,
} }
pub use self::GenericTrackRepeat as TrackRepeat;
impl<L: ToCss, I: ToCss> ToCss for TrackRepeat<L, I> { impl<L: ToCss, I: ToCss> ToCss for TrackRepeat<L, I> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where where
@ -457,46 +492,10 @@ impl<L: ToCss, I: ToCss> ToCss for TrackRepeat<L, I> {
Ok(()) Ok(())
} }
} }
impl<L: Clone> TrackRepeat<L, specified::Integer> {
/// 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 <track-size> or <track-repeat> /// Track list values. Can be <track-size> or <track-repeat>
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive( #[derive(
Animate, Animate,
Clone, Clone,
@ -509,56 +508,63 @@ impl<L: Clone> TrackRepeat<L, specified::Integer> {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
pub enum TrackListValue<LengthPercentage, Integer> { #[repr(C, u8)]
pub enum GenericTrackListValue<LengthPercentage, Integer> {
/// A <track-size> value. /// A <track-size> value.
TrackSize(#[animation(field_bound)] TrackSize<LengthPercentage>), TrackSize(#[animation(field_bound)] GenericTrackSize<LengthPercentage>),
/// A <track-repeat> value. /// A <track-repeat> value.
TrackRepeat(#[animation(field_bound)] TrackRepeat<LengthPercentage, Integer>), TrackRepeat(#[animation(field_bound)] GenericTrackRepeat<LengthPercentage, Integer>),
} }
/// The type of a `<track-list>` as determined during parsing. pub use self::GenericTrackListValue as TrackListValue;
///
/// <https://drafts.csswg.org/css-grid/#typedef-track-list> impl<L, I> TrackListValue<L, I> {
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] fn is_repeat(&self) -> bool {
pub enum TrackListType { matches!(*self, TrackListValue::TrackRepeat(..))
/// [`<auto-track-list>`](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 `<line-names>?` list that comes before `<auto-repeat>`. 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),
/// [`<track-list>`](https://drafts.csswg.org/css-grid/#typedef-track-list)
Normal,
/// [`<explicit-track-list>`](https://drafts.csswg.org/css-grid/#typedef-explicit-track-list)
///
/// Note that this is a subset of the normal `<track-list>`, and so it could be used in place
/// of the latter.
Explicit,
} }
/// A grid `<track-list>` type. /// A grid `<track-list>` type.
/// ///
/// <https://drafts.csswg.org/css-grid/#typedef-track-list> /// <https://drafts.csswg.org/css-grid/#typedef-track-list>
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToResolvedValue, ToShmem)] #[derive(
pub struct TrackList<LengthPercentage, Integer> { Clone,
/// The type of this `<track-list>` (auto, explicit or general). Debug,
/// MallocSizeOf,
/// In order to avoid parsing the same value multiple times, this does a single traversal PartialEq,
/// and arrives at the type of value it has parsed (or bails out gracefully with an error). SpecifiedValueInfo,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct GenericTrackList<LengthPercentage, Integer> {
/// The index in `values` where our `<auto-repeat>` value is, if in bounds.
#[css(skip)] #[css(skip)]
pub list_type: TrackListType, pub auto_repeat_index: usize,
/// A vector of `<track-size> | <track-repeat>` values. /// A vector of `<track-size> | <track-repeat>` values.
pub values: Vec<TrackListValue<LengthPercentage, Integer>>, pub values: crate::OwnedSlice<GenericTrackListValue<LengthPercentage, Integer>>,
/// `<line-names>` accompanying `<track-size> | <track-repeat>` values. /// `<line-names>` accompanying `<track-size> | <track-repeat>` values.
/// ///
/// If there's no `<line-names>`, then it's represented by an empty vector. /// If there's no `<line-names>`, then it's represented by an empty vector.
/// For N values, there will be N+1 `<line-names>`, and so this vector's /// For N values, there will be N+1 `<line-names>`, and so this vector's
/// length is always one value more than that of the `<track-size>`. /// length is always one value more than that of the `<track-size>`.
pub line_names: Box<[Box<[CustomIdent]>]>, pub line_names: crate::OwnedSlice<crate::OwnedSlice<CustomIdent>>,
/// `<auto-repeat>` value. There can only be one `<auto-repeat>` in a TrackList. }
pub auto_repeat: Option<TrackRepeat<LengthPercentage, Integer>>,
pub use self::GenericTrackList as TrackList;
impl<L, I> TrackList<L, I> {
/// 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 `<auto-repeat>` value.
pub fn has_auto_repeat(&self) -> bool {
self.auto_repeat_index < self.values.len()
}
} }
impl<L: ToCss, I: ToCss> ToCss for TrackList<L, I> { impl<L: ToCss, I: ToCss> ToCss for TrackList<L, I> {
@ -566,11 +572,6 @@ impl<L: ToCss, I: ToCss> ToCss for TrackList<L, I> {
where where
W: Write, 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 values_iter = self.values.iter().peekable();
let mut line_names_iter = self.line_names.iter().peekable(); let mut line_names_iter = self.line_names.iter().peekable();
@ -578,15 +579,7 @@ impl<L: ToCss, I: ToCss> ToCss for TrackList<L, I> {
let names = line_names_iter.next().unwrap(); // This should exist! let names = line_names_iter.next().unwrap(); // This should exist!
concat_serialize_idents("[", "]", names, " ", dest)?; concat_serialize_idents("[", "]", names, " ", dest)?;
match self.auto_repeat { match values_iter.next() {
Some(ref repeat) if idx == auto_idx => {
if !names.is_empty() {
dest.write_str(" ")?;
}
repeat.to_css(dest)?;
},
_ => match values_iter.next() {
Some(value) => { Some(value) => {
if !names.is_empty() { if !names.is_empty() {
dest.write_str(" ")?; dest.write_str(" ")?;
@ -595,12 +588,11 @@ impl<L: ToCss, I: ToCss> ToCss for TrackList<L, I> {
value.to_css(dest)?; value.to_css(dest)?;
}, },
None => break, None => break,
},
} }
if values_iter.peek().is_some() || if values_iter.peek().is_some() ||
line_names_iter.peek().map_or(false, |v| !v.is_empty()) || line_names_iter.peek().map_or(false, |v| !v.is_empty()) ||
(idx + 1 == auto_idx) (idx + 1 == self.auto_repeat_index)
{ {
dest.write_str(" ")?; dest.write_str(" ")?;
} }
@ -613,7 +605,8 @@ impl<L: ToCss, I: ToCss> ToCss for TrackList<L, I> {
/// The `<line-name-list>` for subgrids. /// The `<line-name-list>` for subgrids.
/// ///
/// `subgrid [ <line-names> | repeat(<positive-integer> | auto-fill, <line-names>+) ]+` /// `subgrid [ <line-names> | repeat(<positive-integer> | auto-fill, <line-names>+) ]+`
/// 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( #[derive(
Clone, Clone,
Debug, Debug,
@ -625,11 +618,12 @@ impl<L: ToCss, I: ToCss> ToCss for TrackList<L, I> {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(C)]
pub struct LineNameList { pub struct LineNameList {
/// The optional `<line-name-list>` /// The optional `<line-name-list>`
pub names: Box<[Box<[CustomIdent]>]>, pub names: crate::OwnedSlice<crate::OwnedSlice<CustomIdent>>,
/// Indicates the line name that requires `auto-fill` /// Indicates the line name that requires `auto-fill`, if in bounds.
pub fill_idx: Option<u32>, pub fill_idx: usize,
} }
impl Parse for LineNameList { impl Parse for LineNameList {
@ -652,13 +646,17 @@ impl Parse for LineNameList {
while let Ok(names) = input.try(parse_line_names) { while let Ok(names) = input.try(parse_line_names) {
names_list.push(names); names_list.push(names);
} }
Ok((names_list, count)) Ok((names_list, count))
}) })
}); });
if let Ok((mut names_list, count)) = repeat_parse_result { if let Ok((mut names_list, count)) = repeat_parse_result {
match count { 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( RepeatCount::Number(num) => line_names.extend(
names_list names_list
.iter() .iter()
@ -676,7 +674,7 @@ impl Parse for LineNameList {
let names = names_list.pop().unwrap(); let names = names_list.pop().unwrap();
line_names.push(names); 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)), _ => 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 { Ok(LineNameList {
names: line_names.into_boxed_slice(), names: line_names.into(),
fill_idx: fill_idx, fill_idx: fill_idx.unwrap_or(usize::MAX),
}) })
} }
} }
@ -700,7 +702,7 @@ impl ToCss for LineNameList {
W: Write, W: Write,
{ {
dest.write_str("subgrid")?; 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() { for (i, names) in self.names.iter().enumerate() {
if i == fill_idx { if i == fill_idx {
dest.write_str(" repeat(auto-fill,")?; dest.write_str(" repeat(auto-fill,")?;
@ -727,8 +729,8 @@ impl ToCss for LineNameList {
} }
/// Variants for `<grid-template-rows> | <grid-template-columns>` /// Variants for `<grid-template-rows> | <grid-template-columns>`
/// 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( #[derive(
Animate, Animate,
Clone, Clone,
@ -741,7 +743,8 @@ impl ToCss for LineNameList {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
pub enum GridTemplateComponent<L, I> { #[repr(C, u8)]
pub enum GenericGridTemplateComponent<L, I> {
/// `none` value. /// `none` value.
None, None,
/// The grid `<track-list>` /// The grid `<track-list>`
@ -750,14 +753,16 @@ pub enum GridTemplateComponent<L, I> {
#[compute(field_bound)] #[compute(field_bound)]
#[resolve(field_bound)] #[resolve(field_bound)]
#[shmem(field_bound)] #[shmem(field_bound)]
TrackList<L, I>, Box<GenericTrackList<L, I>>,
), ),
/// A `subgrid <line-name-list>?` /// A `subgrid <line-name-list>?`
/// TODO: Support animations for this after subgrid is addressed in [grid-2] spec. /// TODO: Support animations for this after subgrid is addressed in [grid-2] spec.
#[animation(error)] #[animation(error)]
Subgrid(LineNameList), Subgrid(Box<LineNameList>),
} }
pub use self::GenericGridTemplateComponent as GridTemplateComponent;
impl<L, I> GridTemplateComponent<L, I> { impl<L, I> GridTemplateComponent<L, I> {
/// Returns length of the <track-list>s <track-size> /// Returns length of the <track-list>s <track-size>
pub fn track_list_len(&self) -> usize { pub fn track_list_len(&self) -> usize {

View file

@ -41,6 +41,43 @@ impl<H, V> Position<H, V> {
} }
} }
/// A generic type for representing an `Auto | <position>`.
/// This is used by <offset-anchor> 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<Pos> {
/// The <position> value.
Position(Pos),
/// The keyword `auto`.
Auto,
}
pub use self::GenericPositionOrAuto as PositionOrAuto;
impl<Pos> PositionOrAuto<Pos> {
/// Return `auto`.
#[inline]
pub fn auto() -> Self {
PositionOrAuto::Auto
}
}
/// A generic value for the `z-index` property. /// A generic value for the `z-index` property.
#[derive( #[derive(
Animate, Animate,

View file

@ -72,11 +72,8 @@ impl<Value> Spacing<Value> {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
fn line_height_moz_block_height_enabled(context: &ParserContext) -> bool { fn line_height_moz_block_height_enabled(context: &ParserContext) -> bool {
use crate::gecko_bindings::structs;
context.in_ua_sheet() || context.in_ua_sheet() ||
unsafe { static_prefs::pref!("layout.css.line-height-moz-block-height.content.enabled")
structs::StaticPrefs::sVarCache_layout_css_line_height_moz_block_height_content_enabled
}
} }
/// A generic value for the `line-height` property. /// A generic value for the `line-height` property.
@ -125,3 +122,33 @@ impl<N, L> LineHeight<N, L> {
LineHeight::Normal LineHeight::Normal
} }
} }
/// Implements type for text-underline-offset and text-decoration-thickness
/// which take the grammar of auto | from-font | <length>
///
/// 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<L> {
Length(L),
Auto,
FromFont,
}

View file

@ -65,6 +65,7 @@ trivial_to_resolved_value!(u8);
trivial_to_resolved_value!(i8); trivial_to_resolved_value!(i8);
trivial_to_resolved_value!(u16); trivial_to_resolved_value!(u16);
trivial_to_resolved_value!(u32); trivial_to_resolved_value!(u32);
trivial_to_resolved_value!(usize);
trivial_to_resolved_value!(String); trivial_to_resolved_value!(String);
trivial_to_resolved_value!(Box<str>); trivial_to_resolved_value!(Box<str>);
trivial_to_resolved_value!(cssparser::RGBA); trivial_to_resolved_value!(cssparser::RGBA);

View file

@ -58,9 +58,7 @@ pub type Polygon = generic::GenericPolygon<LengthPercentage>;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
fn is_clip_path_path_enabled(context: &ParserContext) -> bool { fn is_clip_path_path_enabled(context: &ParserContext) -> bool {
use crate::gecko_bindings::structs::mozilla; context.chrome_rules_enabled() || static_prefs::pref!("layout.css.clip-path-path.enabled")
context.chrome_rules_enabled() ||
unsafe { mozilla::StaticPrefs::sVarCache_layout_css_clip_path_path_enabled }
} }
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
fn is_clip_path_path_enabled(_: &ParserContext) -> bool { fn is_clip_path_path_enabled(_: &ParserContext) -> bool {

View file

@ -16,6 +16,7 @@ use crate::values::specified::{AllowQuirks, Number};
use crate::values::{CustomIdent, KeyframesName}; use crate::values::{CustomIdent, KeyframesName};
use crate::Atom; use crate::Atom;
use cssparser::Parser; use cssparser::Parser;
use num_traits::FromPrimitive;
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, KeywordsCollectFn, ParseError}; use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
@ -23,102 +24,55 @@ use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
fn moz_display_values_enabled(context: &ParserContext) -> bool { fn moz_display_values_enabled(context: &ParserContext) -> bool {
use crate::gecko_bindings::structs;
context.in_ua_or_chrome_sheet() || 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")] #[cfg(feature = "gecko")]
fn moz_box_display_values_enabled(context: &ParserContext) -> bool { fn moz_box_display_values_enabled(context: &ParserContext) -> bool {
use crate::gecko_bindings::structs;
context.in_ua_or_chrome_sheet() || context.in_ua_or_chrome_sheet() ||
unsafe { static_prefs::pref!("layout.css.xul-box-display-values.content.enabled")
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)
} }
/// Defines an elements display type, which consists of /// Defines an elements display type, which consists of
/// the two basic qualities of how an element generates boxes /// the two basic qualities of how an element generates boxes
/// <https://drafts.csswg.org/css-display/#propdef-display> /// <https://drafts.csswg.org/css-display/#propdef-display>
///
///
/// 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)] #[allow(missing_docs)]
#[derive( #[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)]
Clone,
Copy,
Debug,
Eq,
FromPrimitive,
Hash,
MallocSizeOf,
Parse,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[repr(u8)] #[repr(u8)]
pub enum Display { pub enum DisplayOutside {
None = 0, None = 0,
Inline,
Block, Block,
TableCaption,
InternalTable,
#[cfg(feature = "gecko")] #[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, FlowRoot,
Inline, 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"))]
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, Flex,
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
#[parse(aliases = "-webkit-inline-flex")]
InlineFlex,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
Grid, Grid,
#[cfg(feature = "gecko")] Table,
InlineGrid, TableRowGroup,
TableColumn,
TableColumnGroup,
TableHeaderGroup,
TableFooterGroup,
TableRow,
TableCell,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
Ruby, Ruby,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -130,46 +84,216 @@ pub enum Display {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
RubyTextContainer, RubyTextContainer,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
Contents,
#[cfg(feature = "gecko")]
WebkitBox, WebkitBox,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
WebkitInlineBox,
#[cfg(feature = "gecko")]
#[parse(condition = "moz_box_display_values_enabled")]
MozBox, MozBox,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[parse(condition = "moz_box_display_values_enabled")]
MozInlineBox, MozInlineBox,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[parse(condition = "moz_display_values_enabled")]
MozGrid, MozGrid,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[parse(condition = "moz_display_values_enabled")]
MozInlineGrid, MozInlineGrid,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[parse(condition = "moz_display_values_enabled")]
MozGridGroup, MozGridGroup,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[parse(condition = "moz_display_values_enabled")]
MozGridLine, MozGridLine,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[parse(condition = "moz_display_values_enabled")]
MozStack, MozStack,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[parse(condition = "moz_display_values_enabled")]
MozInlineStack, MozInlineStack,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[parse(condition = "moz_display_values_enabled")]
MozDeck, MozDeck,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[parse(condition = "moz_display_values_enabled")]
MozGroupbox, MozGroupbox,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[parse(condition = "moz_display_values_enabled")]
MozPopup, 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 <display-outside> and <display-inside> 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 <display-outside> and <display-inside> 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 <display-inside> value.
#[inline]
pub fn inside(&self) -> DisplayInside {
DisplayInside::from_u16(self.0 & ((1 << Self::DISPLAY_INSIDE_BITS) - 1)).unwrap()
}
/// Accessor for the <display-outside> 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 { impl Display {
/// The initial display value. /// The initial display value.
#[inline] #[inline]
@ -183,22 +307,20 @@ impl Display {
pub fn is_atomic_inline_level(&self) -> bool { pub fn is_atomic_inline_level(&self) -> bool {
match *self { match *self {
Display::InlineBlock => true, Display::InlineBlock => true,
#[cfg(feature = "servo-layout-2013")]
Display::InlineFlex | Display::InlineTable => true, Display::InlineFlex | Display::InlineTable => true,
_ => false, _ => 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. /// grid container.
/// ///
/// This is used to implement various style fixups. /// This is used to implement various style fixups.
pub fn is_item_container(&self) -> bool { pub fn is_item_container(&self) -> bool {
match *self { match self.inside() {
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] DisplayInside::Flex => true,
Display::Flex | Display::InlineFlex => true,
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
Display::Grid | Display::InlineGrid => true, DisplayInside::Grid => true,
_ => false, _ => 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. /// 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 { 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")] #[cfg(feature = "gecko")]
Display::InlineGrid => Display::Grid, {
#[cfg(feature = "gecko")] // Special handling for `contents` and `list-item`s on the root element.
Display::WebkitInlineBox => Display::WebkitBox, if _is_root_element && (self.is_contents() || self.is_list_item()) {
return Display::Block;
}
}
// Special handling for contents and list-item on the root match self.outside() {
// element for Gecko. DisplayOutside::Inline => {
#[cfg(feature = "gecko")] let inside = match self.inside() {
Display::Contents | Display::ListItem if _is_root_element => Display::Block, DisplayInside::Inline | DisplayInside::FlowRoot => DisplayInside::Block,
inside => inside,
// These are not changed by blockification. };
Display::None | Display::Block => *self, Display::from3(DisplayOutside::Block, inside, self.is_list_item())
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))] },
Display::Flex | Display::ListItem | Display::Table => *self, DisplayOutside::Block | DisplayOutside::None => *self,
#[cfg(feature = "gecko")]
Display::Contents | Display::FlowRoot | Display::Grid | Display::WebkitBox => *self,
// Everything else becomes block.
_ => Display::Block, _ => Display::Block,
} }
} }
/// Convert this display into an inline-outside display. /// Convert this display into an equivalent inline-outside display.
/// /// https://drafts.csswg.org/css-display/#inlinify
/// 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.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub fn inlinify(&self) -> Self { pub fn inlinify(&self) -> Self {
match *self { match self.outside() {
Display::Block | Display::FlowRoot => Display::InlineBlock, DisplayOutside::Block => {
Display::Table => Display::InlineTable, let inside = match self.inside() {
Display::Flex => Display::InlineFlex, DisplayInside::Block => DisplayInside::FlowRoot,
Display::Grid => Display::InlineGrid, inside => inside,
// XXX bug 1105868 this should probably be InlineListItem: };
Display::ListItem => Display::Inline, Display::from3(DisplayOutside::Inline, inside, self.is_list_item())
Display::MozBox => Display::MozInlineBox, },
Display::MozStack => Display::MozInlineStack, #[cfg(feature = "gecko")]
Display::WebkitBox => Display::WebkitInlineBox, DisplayOutside::XUL => match self.inside() {
other => other, DisplayInside::MozBox => Display::MozInlineBox,
DisplayInside::MozStack => Display::MozInlineStack,
_ => *self,
},
_ => *self,
} }
} }
@ -309,6 +401,263 @@ impl Display {
} }
} }
impl ToCss for Display {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> 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)
}
},
},
}
}
}
/// <display-inside> = 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<DisplayInside, ParseError<'i>> {
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,
})
}
/// <display-outside> = 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<DisplayOutside, ParseError<'i>> {
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<DisplayInside, ParseError<'i>> {
Ok(try_match_ident_ignore_ascii_case! { input,
"flow" => DisplayInside::Flow,
#[cfg(feature = "gecko")]
"flow-root" => DisplayInside::FlowRoot,
})
}
/// Test a <display-inside> Result for same values as above.
fn is_valid_inside_for_list_item<'i>(inside: &Result<DisplayInside, ParseError<'i>>) -> 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<Display, ParseError<'i>> {
// Parse all combinations of <display-inside/outside>? 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)
};
// <display-listitem> = <display-outside>? && [ 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 <display-outside> is omitted, the elements 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. /// A specified value for the `vertical-align` property.
pub type VerticalAlign = GenericVerticalAlign<LengthPercentage>; pub type VerticalAlign = GenericVerticalAlign<LengthPercentage>;

View file

@ -6,10 +6,9 @@
//! [grids](https://drafts.csswg.org/css-grid/) //! [grids](https://drafts.csswg.org/css-grid/)
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
use crate::values::computed::{self, Context, ToComputedValue}; use crate::values::generics::grid::{GridTemplateComponent, ImplicitGridTracks, RepeatCount};
use crate::values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth}; use crate::values::generics::grid::{LineNameList, TrackBreadth, TrackRepeat, TrackSize};
use crate::values::generics::grid::{LineNameList, TrackRepeat, TrackSize}; use crate::values::generics::grid::{TrackList, TrackListValue};
use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue};
use crate::values::specified::{Integer, LengthPercentage}; use crate::values::specified::{Integer, LengthPercentage};
use crate::values::{CSSFloat, CustomIdent}; use crate::values::{CSSFloat, CustomIdent};
use cssparser::{ParseError as CssParseError, Parser, Token}; use cssparser::{ParseError as CssParseError, Parser, Token};
@ -96,12 +95,27 @@ impl Parse for TrackSize<LengthPercentage> {
} }
} }
impl Parse for ImplicitGridTracks<TrackSize<LengthPercentage>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
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. /// Parse the grid line names into a vector of owned strings.
/// ///
/// <https://drafts.csswg.org/css-grid/#typedef-line-names> /// <https://drafts.csswg.org/css-grid/#typedef-line-names>
pub fn parse_line_names<'i, 't>( pub fn parse_line_names<'i, 't>(
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Box<[CustomIdent]>, ParseError<'i>> { ) -> Result<crate::OwnedSlice<CustomIdent>, ParseError<'i>> {
input.expect_square_bracket_block()?; input.expect_square_bracket_block()?;
input.parse_nested_block(|input| { input.parse_nested_block(|input| {
let mut values = vec![]; let mut values = vec![];
@ -112,7 +126,7 @@ pub fn parse_line_names<'i, 't>(
values.push(ident); values.push(ident);
} }
Ok(values.into_boxed_slice()) Ok(values.into())
}) })
} }
@ -155,9 +169,7 @@ impl TrackRepeat<LengthPercentage, Integer> {
let mut current_names; let mut current_names;
loop { loop {
current_names = input current_names = input.try(parse_line_names).unwrap_or_default();
.try(parse_line_names)
.unwrap_or(vec![].into_boxed_slice());
if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) { if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
if !track_size.is_fixed() { if !track_size.is_fixed() {
if is_auto { if is_auto {
@ -180,11 +192,7 @@ impl TrackRepeat<LengthPercentage, Integer> {
// one `TrackSize`. But in current version of the spec, this is deprecated // 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 // but we are adding this for gecko parity. We should remove this when
// gecko implements new spec. // gecko implements new spec.
names.push( names.push(input.try(parse_line_names).unwrap_or_default());
input
.try(parse_line_names)
.unwrap_or(vec![].into_boxed_slice()),
);
break; break;
} }
} else { } else {
@ -201,9 +209,9 @@ impl TrackRepeat<LengthPercentage, Integer> {
} }
let repeat = TrackRepeat { let repeat = TrackRepeat {
count: count, count,
track_sizes: values, track_sizes: values.into(),
line_names: names.into_boxed_slice(), line_names: names.into(),
}; };
Ok((repeat, repeat_type)) Ok((repeat, repeat_type))
@ -221,47 +229,31 @@ impl Parse for TrackList<LengthPercentage, Integer> {
let mut names = vec![]; let mut names = vec![];
let mut values = vec![]; let mut values = vec![];
// assume it's the simplest case. // Whether we've parsed an `<auto-repeat>` value.
let mut list_type = TrackListType::Explicit; let mut auto_repeat_index = None;
// holds <auto-repeat> value. It can only be only one in a TrackList.
let mut auto_repeat = None;
// if there is any <auto-repeat> the list will be of type TrackListType::Auto(idx)
// where idx points to the position of the <auto-repeat> in the track list. If there
// is any repeat before <auto-repeat>, we need to take the number of repetitions into
// account to set the position of <auto-repeat> so it remains the same while computing
// values.
let mut auto_offset = 0;
// assume that everything is <fixed-size>. This flag is useful when we encounter <auto-repeat> // assume that everything is <fixed-size>. This flag is useful when we encounter <auto-repeat>
let mut atleast_one_not_fixed = false; let mut at_least_one_not_fixed = false;
loop { loop {
current_names.extend_from_slice( current_names.extend_from_slice(&mut input.try(parse_line_names).unwrap_or_default());
&mut input
.try(parse_line_names)
.unwrap_or(vec![].into_boxed_slice()),
);
if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) { if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) {
if !track_size.is_fixed() { if !track_size.is_fixed() {
atleast_one_not_fixed = true; at_least_one_not_fixed = true;
if auto_repeat.is_some() { if auto_repeat_index.is_some() {
// <auto-track-list> only accepts <fixed-size> and <fixed-repeat> // <auto-track-list> only accepts <fixed-size> and <fixed-repeat>
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
} }
} }
let vec = mem::replace(&mut current_names, vec![]); let vec = mem::replace(&mut current_names, vec![]);
names.push(vec.into_boxed_slice()); names.push(vec.into());
values.push(TrackListValue::TrackSize(track_size)); values.push(TrackListValue::TrackSize(track_size));
} else if let Ok((repeat, type_)) = } else if let Ok((repeat, type_)) =
input.try(|i| TrackRepeat::parse_with_repeat_type(context, i)) input.try(|i| TrackRepeat::parse_with_repeat_type(context, i))
{ {
if list_type == TrackListType::Explicit {
list_type = TrackListType::Normal; // <explicit-track-list> doesn't contain repeat()
}
match type_ { match type_ {
RepeatType::Normal => { RepeatType::Normal => {
atleast_one_not_fixed = true; at_least_one_not_fixed = true;
if auto_repeat.is_some() { if auto_repeat_index.is_some() {
// only <fixed-repeat> // only <fixed-repeat>
return Err( return Err(
input.new_custom_error(StyleParseErrorKind::UnspecifiedError) input.new_custom_error(StyleParseErrorKind::UnspecifiedError)
@ -269,137 +261,42 @@ impl Parse for TrackList<LengthPercentage, Integer> {
} }
}, },
RepeatType::Auto => { 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 <auto-repeat> earlier, or there's at least one non-fixed value // We've either seen <auto-repeat> earlier, or there's at least one non-fixed value
return Err( return Err(
input.new_custom_error(StyleParseErrorKind::UnspecifiedError) input.new_custom_error(StyleParseErrorKind::UnspecifiedError)
); );
} }
auto_repeat_index = Some(values.len());
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;
}, },
RepeatType::Fixed => (), RepeatType::Fixed => {},
} }
let vec = mem::replace(&mut current_names, vec![]); let vec = mem::replace(&mut current_names, vec![]);
names.push(vec.into_boxed_slice()); names.push(vec.into());
if let RepeatCount::Number(num) = repeat.count {
auto_offset += (num.value() - 1) as u16;
}
values.push(TrackListValue::TrackRepeat(repeat)); values.push(TrackListValue::TrackRepeat(repeat));
} else { } 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)); return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
} }
names.push(current_names.into_boxed_slice()); names.push(current_names.into());
break; break;
} }
} }
Ok(TrackList { Ok(TrackList {
list_type: list_type, auto_repeat_index: auto_repeat_index.unwrap_or(std::usize::MAX),
values: values, values: values.into(),
line_names: names.into_boxed_slice(), line_names: names.into(),
auto_repeat: auto_repeat,
}) })
} }
} }
impl ToComputedValue for TrackList<LengthPercentage, Integer> {
type ComputedValue = TrackList<computed::LengthPercentage, computed::Integer>;
#[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 `<track-size>` and one <auto-repeat>.
//
// 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 `<auto-repeat>` value
// set in the `auto_repeat` field, and the `idx` in TrackListType::Auto pointing to the values after
// `<auto-repeat>` (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")] #[cfg(feature = "gecko")]
#[inline] #[inline]
fn allow_grid_template_subgrids() -> bool { fn allow_grid_template_subgrids() -> bool {
use crate::gecko_bindings::structs::mozilla; static_prefs::pref!("layout.css.grid-template-subgrid-value.enabled")
unsafe { mozilla::StaticPrefs::sVarCache_layout_css_grid_template_subgrid_value_enabled }
} }
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
@ -409,7 +306,6 @@ fn allow_grid_template_subgrids() -> bool {
} }
impl Parse for GridTemplateComponent<LengthPercentage, Integer> { impl Parse for GridTemplateComponent<LengthPercentage, Integer> {
// FIXME: Derive Parse (probably with None_)
fn parse<'i, 't>( fn parse<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
@ -430,10 +326,11 @@ impl GridTemplateComponent<LengthPercentage, Integer> {
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
if allow_grid_template_subgrids() { if allow_grid_template_subgrids() {
if let Ok(t) = input.try(|i| LineNameList::parse(context, i)) { 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)))
} }
} }

View file

@ -8,6 +8,7 @@
use super::computed::transform::DirectionVector; use super::computed::transform::DirectionVector;
use super::computed::{Context, ToComputedValue}; 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::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize}; use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize};
use super::generics::transform::IsParallelTo; use super::generics::transform::IsParallelTo;
@ -69,7 +70,7 @@ pub use self::list::Quotes;
pub use self::motion::{OffsetPath, OffsetRotate}; pub use self::motion::{OffsetPath, OffsetRotate};
pub use self::outline::OutlineStyle; pub use self::outline::OutlineStyle;
pub use self::percentage::Percentage; 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::position::{PositionComponent, ZIndex};
pub use self::rect::NonNegativeLengthOrNumberRect; pub use self::rect::NonNegativeLengthOrNumberRect;
pub use self::resolution::Resolution; 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::{InitialLetter, LetterSpacing, LineBreak, LineHeight, TextAlign};
pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak}; pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak};
pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing}; 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::time::Time;
pub use self::transform::{Rotate, Scale, Transform}; pub use self::transform::{Rotate, Scale, Transform};
pub use self::transform::{TransformOrigin, TransformStyle, Translate}; pub use self::transform::{TransformOrigin, TransformStyle, Translate};
@ -626,6 +627,9 @@ pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>;
/// The specified value of a grid `<track-size>` /// The specified value of a grid `<track-size>`
pub type TrackSize = GenericTrackSize<LengthPercentage>; pub type TrackSize = GenericTrackSize<LengthPercentage>;
/// The specified value of a grid `<track-size>+`
pub type ImplicitGridTracks = GenericImplicitGridTracks<TrackSize>;
/// The specified value of a grid `<track-list>` /// The specified value of a grid `<track-list>`
/// (could also be `<auto-track-list>` or `<explicit-track-list>`) /// (could also be `<auto-track-list>` or `<explicit-track-list>`)
pub type TrackList = GenericTrackList<LengthPercentage, Integer>; pub type TrackList = GenericTrackList<LengthPercentage, Integer>;

View file

@ -13,6 +13,7 @@ use crate::str::HTML_SPACE_CHARACTERS;
use crate::values::computed::LengthPercentage as ComputedLengthPercentage; use crate::values::computed::LengthPercentage as ComputedLengthPercentage;
use crate::values::computed::{Context, Percentage, ToComputedValue}; use crate::values::computed::{Context, Percentage, ToComputedValue};
use crate::values::generics::position::Position as GenericPosition; 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::generics::position::ZIndex as GenericZIndex;
use crate::values::specified::{AllowQuirks, Integer, LengthPercentage}; use crate::values::specified::{AllowQuirks, Integer, LengthPercentage};
use crate::Atom; use crate::Atom;
@ -26,6 +27,9 @@ use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
/// The specified value of a CSS `<position>` /// The specified value of a CSS `<position>`
pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>; pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>;
/// The specified value of an `auto | <position>`.
pub type PositionOrAuto = GenericPositionOrAuto<Position>;
/// The specified value of a horizontal position. /// The specified value of a horizontal position.
pub type HorizontalPosition = PositionComponent<HorizontalPositionKeyword>; pub type HorizontalPosition = PositionComponent<HorizontalPositionKeyword>;

View file

@ -32,8 +32,7 @@ pub type SVGStrokeDashArray = generic::SVGStrokeDashArray<NonNegativeLengthPerce
/// Whether the `context-value` value is enabled. /// Whether the `context-value` value is enabled.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub fn is_context_value_enabled() -> bool { pub fn is_context_value_enabled() -> bool {
use crate::gecko_bindings::structs::mozilla; static_prefs::pref!("gfx.font_rendering.opentype_svg.enabled")
unsafe { mozilla::StaticPrefs::sVarCache_gfx_font_rendering_opentype_svg_enabled }
} }
/// Whether the `context-value` value is enabled. /// Whether the `context-value` value is enabled.

View file

@ -625,40 +625,26 @@ impl<'a> PathParser<'a> {
break; break;
} }
match self.chars.next() { let command = self.chars.next().unwrap();
Some(command) => {
let abs = if command.is_ascii_uppercase() { let abs = if command.is_ascii_uppercase() {
IsAbsolute::Yes IsAbsolute::Yes
} else { } else {
IsAbsolute::No IsAbsolute::No
}; };
macro_rules! parse_command {
( $($($p:pat)|+ => $parse_func:ident,)* ) => {
match command {
$(
$($p)|+ => {
skip_wsp(&mut self.chars); skip_wsp(&mut self.chars);
self.$parse_func(abs)?; 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(()), _ => 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.
}
} }
Ok(()) Ok(())
} }
@ -692,7 +678,7 @@ impl<'a> PathParser<'a> {
} }
/// Parse "closepath" command. /// Parse "closepath" command.
fn parse_closepath(&mut self, _absolute: IsAbsolute) -> Result<(), ()> { fn parse_closepath(&mut self) -> Result<(), ()> {
self.path.push(PathCommand::ClosePath); self.path.push(PathCommand::ClosePath);
Ok(()) Ok(())
} }

View file

@ -7,13 +7,12 @@
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
use crate::properties::longhands::writing_mode::computed_value::T as SpecifiedWritingMode; use crate::properties::longhands::writing_mode::computed_value::T as SpecifiedWritingMode;
use crate::values::computed::text::LineHeight as ComputedLineHeight; 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::TextEmphasisStyle as ComputedTextEmphasisStyle;
use crate::values::computed::text::TextOverflow as ComputedTextOverflow; use crate::values::computed::text::TextOverflow as ComputedTextOverflow;
use crate::values::computed::{Context, ToComputedValue}; use crate::values::computed::{Context, ToComputedValue};
use crate::values::generics::text::InitialLetter as GenericInitialLetter; use crate::values::generics::text::InitialLetter as GenericInitialLetter;
use crate::values::generics::text::LineHeight as GenericLineHeight; 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::NonNegativeLengthPercentage;
use crate::values::specified::length::{FontRelativeLength, Length}; use crate::values::specified::length::{FontRelativeLength, Length};
use crate::values::specified::length::{LengthPercentage, NoCalcLength}; 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<TextEmphasisShapeKeyword>,
) -> bool {
shape.is_some() && fill.is_filled()
}
/// Specified value of text-emphasis-style property. /// 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)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
#[allow(missing_docs)]
pub enum TextEmphasisStyle { pub enum TextEmphasisStyle {
/// <fill> <shape> /// [ <fill> || <shape> ]
Keyword(TextEmphasisKeywordValue), Keyword {
#[css(contextual_skip_if = "fill_mode_is_default_and_shape_exists")]
fill: TextEmphasisFillMode,
shape: Option<TextEmphasisShapeKeyword>,
},
/// `none` /// `none`
None, None,
/// String (will be used only first grapheme cluster) for the text-emphasis-style property /// `<string>` (of which only the first grapheme cluster will be used).
String(String), String(crate::OwnedStr),
}
/// Keyword value for the text-emphasis-style property
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
pub enum TextEmphasisKeywordValue {
/// <fill>
Fill(TextEmphasisFillMode),
/// <shape>
Shape(TextEmphasisShapeKeyword),
/// <fill> <shape>
FillAndShape(TextEmphasisFillMode, TextEmphasisShapeKeyword),
}
impl TextEmphasisKeywordValue {
fn fill(&self) -> Option<TextEmphasisFillMode> {
match *self {
TextEmphasisKeywordValue::Fill(fill) |
TextEmphasisKeywordValue::FillAndShape(fill, _) => Some(fill),
_ => None,
}
}
fn shape(&self) -> Option<TextEmphasisShapeKeyword> {
match *self {
TextEmphasisKeywordValue::Shape(shape) |
TextEmphasisKeywordValue::FillAndShape(_, shape) => Some(shape),
_ => None,
}
}
} }
/// Fill mode for the text-emphasis-style property /// Fill mode for the text-emphasis-style property
#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] #[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
#[repr(u8)]
pub enum TextEmphasisFillMode { pub enum TextEmphasisFillMode {
/// `filled` /// `filled`
Filled, Filled,
@ -694,10 +679,19 @@ pub enum TextEmphasisFillMode {
Open, 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 /// Shape keyword for the text-emphasis-style property
#[derive( #[derive(
Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem,
)] )]
#[repr(u8)]
pub enum TextEmphasisShapeKeyword { pub enum TextEmphasisShapeKeyword {
/// `dot` /// `dot`
Dot, Dot,
@ -711,77 +705,39 @@ pub enum TextEmphasisShapeKeyword {
Sesame, 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 { impl ToComputedValue for TextEmphasisStyle {
type ComputedValue = ComputedTextEmphasisStyle; type ComputedValue = ComputedTextEmphasisStyle;
#[inline] #[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self { match *self {
TextEmphasisStyle::Keyword(ref keyword) => { TextEmphasisStyle::Keyword { fill, shape } => {
// FIXME(emilio): This should set the rule_cache_conditions let shape = shape.unwrap_or_else(|| {
// properly. // FIXME(emilio, bug 1572958): This should set the
let default_shape = if context.style().get_inherited_box().clone_writing_mode() == // 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 SpecifiedWritingMode::HorizontalTb
{ {
TextEmphasisShapeKeyword::Circle TextEmphasisShapeKeyword::Circle
} else { } else {
TextEmphasisShapeKeyword::Sesame TextEmphasisShapeKeyword::Sesame
}; }
ComputedTextEmphasisStyle::Keyword(ComputedTextEmphasisKeywordValue { });
fill: keyword.fill().unwrap_or(TextEmphasisFillMode::Filled), ComputedTextEmphasisStyle::Keyword { fill, shape }
shape: keyword.shape().unwrap_or(default_shape),
})
}, },
TextEmphasisStyle::None => ComputedTextEmphasisStyle::None, TextEmphasisStyle::None => ComputedTextEmphasisStyle::None,
TextEmphasisStyle::String(ref s) => { TextEmphasisStyle::String(ref s) => {
// Passing `true` to iterate over extended grapheme clusters, following // Passing `true` to iterate over extended grapheme clusters, following
// recommendation at http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries // 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] #[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self { fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed { match *computed {
ComputedTextEmphasisStyle::Keyword(ref keyword) => TextEmphasisStyle::Keyword( ComputedTextEmphasisStyle::Keyword { fill, shape } => TextEmphasisStyle::Keyword {
TextEmphasisKeywordValue::FillAndShape(keyword.fill, keyword.shape), fill,
), shape: Some(shape),
},
ComputedTextEmphasisStyle::None => TextEmphasisStyle::None, ComputedTextEmphasisStyle::None => TextEmphasisStyle::None,
ComputedTextEmphasisStyle::String(ref string) => { ComputedTextEmphasisStyle::String(ref string) => {
TextEmphasisStyle::String(string.clone()) 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())) { if let Ok(s) = input.try(|i| i.expect_string().map(|s| s.as_ref().to_owned())) {
// Handle <string> // Handle <string>
return Ok(TextEmphasisStyle::String(s)); return Ok(TextEmphasisStyle::String(s.into()));
} }
// Handle a pair of keywords // Handle a pair of keywords
@ -824,14 +781,17 @@ impl Parse for TextEmphasisStyle {
shape = input.try(TextEmphasisShapeKeyword::parse).ok(); shape = input.try(TextEmphasisShapeKeyword::parse).ok();
} }
// At least one of shape or fill must be handled if shape.is_none() && fill.is_none() {
let keyword_value = match (fill, shape) { return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
(Some(fill), Some(shape)) => TextEmphasisKeywordValue::FillAndShape(fill, shape), }
(Some(fill), None) => TextEmphasisKeywordValue::Fill(fill),
(None, Some(shape)) => TextEmphasisKeywordValue::Shape(shape), // If a shape keyword is specified but neither filled nor open is
_ => return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)), // specified, filled is assumed.
}; let fill = fill.unwrap_or(TextEmphasisFillMode::Filled);
Ok(TextEmphasisStyle::Keyword(keyword_value))
// We cannot do the same because the default `<shape>` depends on the
// computed writing-mode.
Ok(TextEmphasisStyle::Keyword { fill, shape })
} }
} }
@ -1079,3 +1039,20 @@ pub enum TextDecorationSkipInk {
Auto, Auto,
None, None,
} }
/// Implements type for `text-underline-offset` and `text-decoration-thickness` properties
pub type TextDecorationLength = GenericTextDecorationLength<Length>;
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)
}
}

View file

@ -199,7 +199,9 @@ pub enum CursorKind {
Move, Move,
NoDrop, NoDrop,
NotAllowed, NotAllowed,
#[parse(aliases = "-moz-grab")]
Grab, Grab,
#[parse(aliases = "-moz-grabbing")]
Grabbing, Grabbing,
EResize, EResize,
NResize, NResize,
@ -216,15 +218,9 @@ pub enum CursorKind {
ColResize, ColResize,
RowResize, RowResize,
AllScroll, AllScroll,
#[parse(aliases = "-moz-zoom-in")]
ZoomIn, ZoomIn,
#[parse(aliases = "-moz-zoom-out")]
ZoomOut, ZoomOut,
Auto, Auto,
#[cfg(feature = "gecko")]
MozGrab,
#[cfg(feature = "gecko")]
MozGrabbing,
#[cfg(feature = "gecko")]
MozZoomIn,
#[cfg(feature = "gecko")]
MozZoomOut,
} }

View file

@ -82,6 +82,7 @@ impl SpecifiedValueInfo for i32 {}
impl SpecifiedValueInfo for u8 {} impl SpecifiedValueInfo for u8 {}
impl SpecifiedValueInfo for u16 {} impl SpecifiedValueInfo for u16 {}
impl SpecifiedValueInfo for u32 {} impl SpecifiedValueInfo for u32 {}
impl SpecifiedValueInfo for usize {}
impl SpecifiedValueInfo for str {} impl SpecifiedValueInfo for str {}
impl SpecifiedValueInfo for String {} impl SpecifiedValueInfo for String {}
impl SpecifiedValueInfo for crate::owned_str::OwnedStr {} impl SpecifiedValueInfo for crate::owned_str::OwnedStr {}

View file

@ -56,6 +56,7 @@ files = [
"./components/net/tests/parsable_mime/text", "./components/net/tests/parsable_mime/text",
# Mako does not lend itself easily to splitting long lines # Mako does not lend itself easily to splitting long lines
"./components/style/properties/helpers/animated_properties.mako.rs", "./components/style/properties/helpers/animated_properties.mako.rs",
"./components/style/properties/shorthands/text.mako.rs",
# Long regexes are long. # Long regexes are long.
"./components/style/gecko/regen_atoms.py", "./components/style/gecko/regen_atoms.py",
# Helper macro where actually a pseudo-element per line makes sense. # Helper macro where actually a pseudo-element per line makes sense.

View file

@ -1,2 +0,0 @@
[font-weight-xxx-large.html]
expected: FAIL

View file

@ -1,4 +0,0 @@
[font-size-valid.html]
[e.style['font-size'\] = "xxx-large" should set the property value]
expected: FAIL

View file

@ -44,9 +44,6 @@
[display: table-row-group] [display: table-row-group]
expected: FAIL expected: FAIL
[display: flow]
expected: FAIL
[display: table-column-group] [display: table-column-group]
expected: FAIL expected: FAIL