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