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