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

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/22352)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-12-02 19:07:23 -05:00 committed by GitHub
commit 5bdea7dc1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 2100 additions and 1984 deletions

View file

@ -1499,8 +1499,11 @@ impl FragmentDisplayListBuilding for Fragment {
let outline_style = match style.get_outline().outline_style {
OutlineStyle::Auto => BorderStyle::Solid,
OutlineStyle::Other(BorderStyle::None) => return,
OutlineStyle::Other(border_style) => border_style,
// FIXME(emilio): I don't think this border-style check is
// necessary, since border-style: none implies an outline-width of
// zero at computed value time.
OutlineStyle::BorderStyle(BorderStyle::None) => return,
OutlineStyle::BorderStyle(s) => s,
};
// Outlines are not accounted for in the dimensions of the border box, so adjust the

View file

@ -31,6 +31,7 @@ include = ["cssparser"]
[struct]
derive_eq = true
derive_neq = true
[enum]
derive_helper_methods = true
@ -41,6 +42,8 @@ include = [
"Appearance",
"BreakBetween",
"BreakWithin",
"BorderStyle",
"OutlineStyle",
"ComputedFontStretchRange",
"ComputedFontStyleDescriptor",
"ComputedFontWeightRange",

View file

@ -283,18 +283,32 @@ impl VariableValue {
}
}
fn push(
fn push<'i>(
&mut self,
input: &Parser<'i, '_>,
css: &str,
css_first_token_type: TokenSerializationType,
css_last_token_type: TokenSerializationType,
) {
) -> Result<(), ParseError<'i>> {
/// Prevent values from getting terribly big since you can use custom
/// properties exponentially.
///
/// This number (1MB) is somewhat arbitrary, but silly enough that no
/// sane page would hit it. We could limit by number of total
/// substitutions, but that was very easy to work around in practice
/// (just choose a larger initial value and boom).
const MAX_VALUE_LENGTH_IN_BYTES: usize = 1024 * 1024;
if self.css.len() + css.len() > MAX_VALUE_LENGTH_IN_BYTES {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
// This happens e.g. between two subsequent var() functions:
// `var(--a)var(--b)`.
//
// In that case, css_*_token_type is nonsensical.
if css.is_empty() {
return;
return Ok(());
}
self.first_token_type.set_if_nothing(css_first_token_type);
@ -307,21 +321,32 @@ impl VariableValue {
self.css.push_str("/**/")
}
self.css.push_str(css);
self.last_token_type = css_last_token_type
self.last_token_type = css_last_token_type;
Ok(())
}
fn push_from(
fn push_from<'i>(
&mut self,
input: &Parser<'i, '_>,
position: (SourcePosition, TokenSerializationType),
input: &Parser,
last_token_type: TokenSerializationType,
) {
self.push(input.slice_from(position.0), position.1, last_token_type)
) -> Result<(), ParseError<'i>> {
self.push(
input,
input.slice_from(position.0),
position.1,
last_token_type,
)
}
fn push_variable(&mut self, variable: &ComputedValue) {
fn push_variable<'i>(
&mut self,
input: &Parser<'i, '_>,
variable: &ComputedValue,
) -> Result<(), ParseError<'i>> {
debug_assert!(variable.references.is_empty());
self.push(
input,
&variable.css,
variable.first_token_type,
variable.last_token_type,
@ -727,6 +752,7 @@ fn substitute_all(custom_properties_map: &mut CustomPropertiesMap, environment:
// title=Tarjan%27s_strongly_connected_components_algorithm&oldid=801728495
/// Struct recording necessary information for each variable.
#[derive(Debug)]
struct VarInfo {
/// The name of the variable. It will be taken to save addref
/// when the corresponding variable is popped from the stack.
@ -741,6 +767,7 @@ fn substitute_all(custom_properties_map: &mut CustomPropertiesMap, environment:
}
/// Context struct for traversing the variable graph, so that we can
/// avoid referencing all the fields multiple times.
#[derive(Debug)]
struct Context<'a> {
/// Number of variables visited. This is used as the order index
/// when we visit a new unresolved variable.
@ -941,7 +968,7 @@ fn substitute_references_in_value<'i>(
environment,
)?;
computed_value.push_from(position, &input, last_token_type);
computed_value.push_from(&input, position, last_token_type)?;
Ok(computed_value)
}
@ -955,8 +982,8 @@ fn substitute_references_in_value<'i>(
///
/// Return `Err(())` if `input` is invalid at computed-value time.
/// or `Ok(last_token_type that was pushed to partial_computed_value)` otherwise.
fn substitute_block<'i, 't>(
input: &mut Parser<'i, 't>,
fn substitute_block<'i>(
input: &mut Parser<'i, '_>,
position: &mut (SourcePosition, TokenSerializationType),
partial_computed_value: &mut ComputedValue,
custom_properties: &CustomPropertiesMap,
@ -991,10 +1018,11 @@ fn substitute_block<'i, 't>(
let is_env = name.eq_ignore_ascii_case("env");
partial_computed_value.push(
input,
input.slice(position.0..before_this_token),
position.1,
last_token_type,
);
)?;
input.parse_nested_block(|input| {
// parse_var_function() / parse_env_function() ensure neither .unwrap() will fail.
let name = {
@ -1014,7 +1042,7 @@ fn substitute_block<'i, 't>(
if let Some(v) = value {
last_token_type = v.last_token_type;
partial_computed_value.push_variable(v);
partial_computed_value.push_variable(input, v)?;
// Skip over the fallback, as `parse_nested_block` would return `Err`
// if we don't consume all of `input`.
// FIXME: Add a specialized method to cssparser to do this with less work.
@ -1036,7 +1064,7 @@ fn substitute_block<'i, 't>(
custom_properties,
env,
)?;
partial_computed_value.push_from(position, input, last_token_type);
partial_computed_value.push_from(input, position, last_token_type)?;
}
Ok(())
})?;
@ -1096,6 +1124,6 @@ pub fn substitute<'i>(
&custom_properties,
env,
)?;
substituted.push_from(position, &input, last_token_type);
substituted.push_from(&input, position, last_token_type)?;
Ok(substituted.css)
}

View file

@ -11,11 +11,13 @@
use app_units::Au;
use crate::gecko::values::GeckoStyleCoordConvertible;
use crate::gecko_bindings::bindings;
use crate::gecko_bindings::structs::RawGeckoGfxMatrix4x4;
use crate::gecko_bindings::structs::{self, nsStyleCoord_CalcValue};
use crate::gecko_bindings::structs::{nsStyleImage, nsresult, SheetType};
use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
use crate::stylesheets::{Origin, RulesMutateError};
use crate::values::computed::image::LineDirection;
use crate::values::computed::transform::Matrix3D;
use crate::values::computed::url::ComputedImageUrl;
use crate::values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image};
use crate::values::computed::{Integer, LengthOrPercentage};
@ -1142,3 +1144,36 @@ pub unsafe fn string_from_chars_pointer(p: *const u16) -> String {
let char_vec = slice::from_raw_parts(p, length as usize);
String::from_utf16_lossy(char_vec)
}
impl<'a> From<&'a RawGeckoGfxMatrix4x4> for Matrix3D {
fn from(m: &'a RawGeckoGfxMatrix4x4) -> Matrix3D {
Matrix3D {
m11: m[0],
m12: m[1],
m13: m[2],
m14: m[3],
m21: m[4],
m22: m[5],
m23: m[6],
m24: m[7],
m31: m[8],
m32: m[9],
m33: m[10],
m34: m[11],
m41: m[12],
m42: m[13],
m43: m[14],
m44: m[15],
}
}
}
impl From<Matrix3D> for RawGeckoGfxMatrix4x4 {
fn from(matrix: Matrix3D) -> RawGeckoGfxMatrix4x4 {
[
matrix.m11, matrix.m12, matrix.m13, matrix.m14, matrix.m21, matrix.m22, matrix.m23,
matrix.m24, matrix.m31, matrix.m32, matrix.m33, matrix.m34, matrix.m41, matrix.m42,
matrix.m43, matrix.m44,
]
}
}

View file

@ -462,22 +462,6 @@ impl PropertyDeclarationBlock {
return false;
}
// As a compatibility hack, specially on Android,
// don't allow to override a prefixed webkit display
// value with an unprefixed version from parsing
// code.
//
// TODO(emilio): Unship.
if let PropertyDeclaration::Display(old_display) = *slot {
use crate::properties::longhands::display::computed_value::T as display;
if let PropertyDeclaration::Display(new_display) = declaration {
if display::should_ignore_parsed_value(old_display, new_display) {
return false;
}
}
}
index_to_remove = Some(i);
break;
}
@ -933,6 +917,10 @@ impl PropertyDeclarationBlock {
}
already_serialized.insert(shorthand.into());
if shorthand.is_legacy_shorthand() {
continue;
}
// Substep 2 & 3
let mut current_longhands = SmallVec::<[_; 10]>::new();
let mut important_count = 0;

View file

@ -58,15 +58,14 @@ use std::mem::{forget, uninitialized, transmute, zeroed};
use std::{cmp, ops, ptr};
use crate::values::{self, CustomIdent, Either, KeyframesName, None_};
use crate::values::computed::{NonNegativeLength, Percentage, TransitionProperty};
use crate::values::computed::BorderStyle;
use crate::values::computed::font::FontSize;
use crate::values::computed::effects::{BoxShadow, Filter, SimpleShadow};
use crate::values::computed::outline::OutlineStyle;
use crate::values::generics::column::ColumnCount;
use crate::values::generics::position::ZIndex;
use crate::values::generics::text::MozTabSize;
use crate::values::generics::transform::TransformStyle;
use crate::values::generics::url::UrlOrNone;
use crate::computed_values::border_style;
pub mod style_structs {
% for style_struct in data.style_structs:
@ -333,13 +332,10 @@ impl ${style_struct.gecko_struct_name} {
}
</%def>
<%def name="impl_simple_copy(ident, gecko_ffi_name, on_set=None, *kwargs)">
<%def name="impl_simple_copy(ident, gecko_ffi_name, *kwargs)">
#[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) {
self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name};
% if on_set:
self.${on_set}();
% endif
}
#[allow(non_snake_case)]
@ -368,7 +364,7 @@ def set_gecko_property(ffi_name, expr):
return "self.gecko.%s = %s;" % (ffi_name, expr)
%>
<%def name="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type='u8', on_set=None)">
<%def name="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type='u8')">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
use crate::properties::longhands::${ident}::computed_value::T as Keyword;
@ -380,9 +376,6 @@ def set_gecko_property(ffi_name, expr):
% endfor
};
${set_gecko_property(gecko_ffi_name, "result")}
% if on_set:
self.${on_set}();
% endif
}
</%def>
@ -1515,9 +1508,6 @@ fn static_assert() {
}
<% border_style_keyword = Keyword("border-style",
"none solid double dotted dashed hidden groove ridge inset outset") %>
<% skip_border_longhands = " ".join(["border-{0}-{1}".format(x.ident, y)
for x in SIDES
for y in ["color", "style", "width"]] +
@ -1528,41 +1518,55 @@ fn static_assert() {
skip_longhands="${skip_border_longhands} border-image-source border-image-outset
border-image-repeat border-image-width border-image-slice">
% for side in SIDES:
<% impl_keyword("border_%s_style" % side.ident,
"mBorderStyle[%s]" % side.index,
border_style_keyword,
on_set="update_border_%s" % side.ident) %>
pub fn set_border_${side.ident}_style(&mut self, v: BorderStyle) {
self.gecko.mBorderStyle[${side.index}] = v;
// This is needed because the initial mComputedBorder value is set to zero.
//
// In order to compute stuff, we start from the initial struct, and keep
// going down the tree applying properties.
//
// That means, effectively, that when we set border-style to something
// non-hidden, we should use the initial border instead.
//
// Servo stores the initial border-width in the initial struct, and then
// adjusts as needed in the fixup phase. This means that the initial struct
// is technically not valid without fixups, and that you lose pretty much
// any sharing of the initial struct, which is kind of unfortunate.
//
// Gecko has two fields for this, one that stores the "specified" border,
// and other that stores the actual computed one. That means that when we
// set border-style, border-width may change and we need to sync back to the
// specified one. This is what this function does.
//
// Note that this doesn't impose any dependency in the order of computation
// of the properties. This is only relevant if border-style is specified,
// but border-width isn't. If border-width is specified at some point, the
// two mBorder and mComputedBorder fields would be the same already.
//
// Once we're here, we know that we'll run style fixups, so it's fine to
// just copy the specified border here, we'll adjust it if it's incorrect
// later.
fn update_border_${side.ident}(&mut self) {
// This is needed because the initial mComputedBorder value is set to
// zero.
//
// In order to compute stuff, we start from the initial struct, and keep
// going down the tree applying properties.
//
// That means, effectively, that when we set border-style to something
// non-hidden, we should use the initial border instead.
//
// Servo stores the initial border-width in the initial struct, and then
// adjusts as needed in the fixup phase. This means that the initial
// struct is technically not valid without fixups, and that you lose
// pretty much any sharing of the initial struct, which is kind of
// unfortunate.
//
// Gecko has two fields for this, one that stores the "specified"
// border, and other that stores the actual computed one. That means
// that when we set border-style, border-width may change and we need to
// sync back to the specified one. This is what this function does.
//
// Note that this doesn't impose any dependency in the order of
// computation of the properties. This is only relevant if border-style
// is specified, but border-width isn't. If border-width is specified at
// some point, the two mBorder and mComputedBorder fields would be the
// same already.
//
// Once we're here, we know that we'll run style fixups, so it's fine to
// just copy the specified border here, we'll adjust it if it's
// incorrect later.
self.gecko.mComputedBorder.${side.ident} = self.gecko.mBorder.${side.ident};
}
pub fn copy_border_${side.ident}_style_from(&mut self, other: &Self) {
self.gecko.mBorderStyle[${side.index}] = other.gecko.mBorderStyle[${side.index}];
self.gecko.mComputedBorder.${side.ident} = self.gecko.mBorder.${side.ident};
}
pub fn reset_border_${side.ident}_style(&mut self, other: &Self) {
self.copy_border_${side.ident}_style_from(other);
}
#[inline]
pub fn clone_border_${side.ident}_style(&self) -> BorderStyle {
self.gecko.mBorderStyle[${side.index}]
}
<% impl_color("border_%s_color" % side.ident, "mBorder%sColor" % side.name) %>
<% impl_non_negative_length("border_%s_width" % side.ident,
@ -2170,50 +2174,26 @@ fn static_assert() {
<%self:impl_trait style_struct_name="Outline"
skip_longhands="${skip_outline_longhands}">
#[allow(non_snake_case)]
pub fn set_outline_style(&mut self, v: longhands::outline_style::computed_value::T) {
// FIXME(bholley): Align binary representations and ditch |match| for
// cast + static_asserts
let result = match v {
% for value in border_style_keyword.values_for('gecko'):
OutlineStyle::Other(border_style::T::${to_camel_case(value)}) =>
structs::${border_style_keyword.gecko_constant(value)} ${border_style_keyword.maybe_cast("u8")},
% endfor
OutlineStyle::Auto =>
structs::${border_style_keyword.gecko_constant('auto')} ${border_style_keyword.maybe_cast("u8")},
};
${set_gecko_property("mOutlineStyle", "result")}
self.gecko.mOutlineStyle = v;
// NB: This is needed to correctly handling the initial value of
// outline-width when outline-style changes, see the
// update_border_${side.ident} comment for more details.
self.gecko.mActualOutlineWidth = self.gecko.mOutlineWidth;
}
#[allow(non_snake_case)]
pub fn copy_outline_style_from(&mut self, other: &Self) {
// FIXME(emilio): Why doesn't this need to reset mActualOutlineWidth?
// Looks fishy.
self.gecko.mOutlineStyle = other.gecko.mOutlineStyle;
}
#[allow(non_snake_case)]
pub fn reset_outline_style(&mut self, other: &Self) {
self.copy_outline_style_from(other)
}
#[allow(non_snake_case)]
pub fn clone_outline_style(&self) -> longhands::outline_style::computed_value::T {
// FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts
match ${get_gecko_property("mOutlineStyle")} ${border_style_keyword.maybe_cast("u32")} {
% for value in border_style_keyword.values_for('gecko'):
structs::${border_style_keyword.gecko_constant(value)} => {
OutlineStyle::Other(border_style::T::${to_camel_case(value)})
},
% endfor
structs::${border_style_keyword.gecko_constant('auto')} => OutlineStyle::Auto,
% if border_style_keyword.gecko_inexhaustive:
_ => panic!("Found unexpected value in style struct for outline_style property"),
% endif
}
self.gecko.mOutlineStyle.clone()
}
<% impl_non_negative_length("outline_width", "mActualOutlineWidth",
@ -5410,7 +5390,7 @@ clip-path
</%self:impl_trait>
<%self:impl_trait style_struct_name="Column"
skip_longhands="column-count column-rule-width">
skip_longhands="column-count column-rule-width column-rule-style">
#[allow(unused_unsafe)]
pub fn set_column_count(&mut self, v: longhands::column_count::computed_value::T) {
@ -5439,6 +5419,7 @@ clip-path
<% impl_non_negative_length("column_rule_width", "mColumnRuleWidth",
round_to_pixels=True) %>
${impl_simple('column_rule_style', 'mColumnRuleStyle')}
</%self:impl_trait>
<%self:impl_trait style_struct_name="Counters"

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,8 @@ ${helpers.predefined_type(
animation_value_type="AnimatedColor",
ignored_when_colors_disabled=True,
allow_quirks=True,
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER \
CAN_ANIMATE_ON_COMPOSITOR",
)}
${helpers.predefined_type(

View file

@ -63,7 +63,9 @@
${helpers.gecko_keyword_conversion(
Keyword('border-style',
"none solid double dotted dashed hidden groove ridge inset outset"),
"none solid double dotted dashed hidden groove ridge inset outset",
gecko_enum_prefix="StyleBorderStyle",
gecko_inexhaustive=True),
type="crate::values::specified::BorderStyle",
)}

View file

@ -438,33 +438,33 @@ ${helpers.single_keyword(
)}
${helpers.predefined_type(
"page-break-after",
"break-after",
"BreakBetween",
"computed::BreakBetween::Auto",
needs_context=False,
products="gecko",
spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-after",
spec="https://drafts.csswg.org/css-break/#propdef-break-after",
animation_value_type="discrete",
)}
${helpers.predefined_type(
"page-break-before",
"break-before",
"BreakBetween",
"computed::BreakBetween::Auto",
needs_context=False,
products="gecko",
spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-before",
spec="https://drafts.csswg.org/css-break/#propdef-break-before",
animation_value_type="discrete",
)}
${helpers.predefined_type(
"page-break-inside",
"break-inside",
"BreakWithin",
"computed::BreakWithin::Auto",
gecko_ffi_name="mBreakInside",
needs_context=False,
products="gecko",
spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-inside",
alias="page-break-inside",
spec="https://drafts.csswg.org/css-break/#propdef-break-inside",
animation_value_type="discrete",
)}

View file

@ -78,12 +78,14 @@ ${helpers.single_keyword(
extra_prefixes="moz:layout.css.column-span.enabled",
)}
${helpers.single_keyword(
${helpers.predefined_type(
"column-rule-style",
"none hidden dotted dashed solid double groove ridge inset outset",
"BorderStyle",
"computed::BorderStyle::None",
needs_context=False,
initial_specified_value="specified::BorderStyle::None",
products="gecko",
extra_prefixes="moz",
gecko_constant_prefix="NS_STYLE_BORDER_STYLE",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-style",
)}

View file

@ -337,6 +337,7 @@ ${helpers.single_keyword(
${helpers.single_keyword(
"text-rendering",
"auto optimizespeed optimizelegibility geometricprecision",
gecko_enum_prefix="StyleTextRendering",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty",
servo_restyle_damage="rebuild_and_reflow",

View file

@ -39,6 +39,7 @@ ${helpers.predefined_type(
gecko_ffi_name="mUserSelect",
alias="-webkit-user-select",
animation_value_type="discrete",
needs_context=False,
spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select",
)}

View file

@ -948,6 +948,10 @@ bitflags! {
/// This property's getComputedStyle implementation requires layout
/// to be flushed.
const GETCS_NEEDS_LAYOUT_FLUSH = 1 << 6;
/// This property is a legacy shorthand.
///
/// https://drafts.csswg.org/css-cascade/#legacy-shorthand
const IS_LEGACY_SHORTHAND = 1 << 7;
/* The following flags are currently not used in Rust code, they
* only need to be listed in corresponding properties so that
@ -1461,17 +1465,24 @@ impl ShorthandId {
None
}
/// Returns PropertyFlags for given shorthand property.
pub fn flags(&self) -> PropertyFlags {
match *self {
/// Returns PropertyFlags for the given shorthand property.
#[inline]
pub fn flags(self) -> PropertyFlags {
const FLAGS: [u8; ${len(data.shorthands)}] = [
% for property in data.shorthands:
ShorthandId::${property.camel_case} =>
% for flag in property.flags:
PropertyFlags::${flag} |
% endfor
PropertyFlags::empty(),
% for flag in property.flags:
PropertyFlags::${flag}.bits |
% endfor
0,
% endfor
}
];
PropertyFlags::from_bits_truncate(FLAGS[self as usize])
}
/// Returns whether this property is a legacy shorthand.
#[inline]
pub fn is_legacy_shorthand(self) -> bool {
self.flags().contains(PropertyFlags::IS_LEGACY_SHORTHAND)
}
/// Returns the order in which this property appears relative to other

View file

@ -447,3 +447,51 @@ macro_rules! try_parse_one {
}
}
</%helpers:shorthand>
<%helpers:shorthand
name="page-break-before"
products="gecko"
flags="SHORTHAND_IN_GETCS IS_LEGACY_SHORTHAND"
sub_properties="break-before"
spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-before"
>
pub fn parse_value<'i>(
_: &ParserContext,
input: &mut Parser<'i, '_>,
) -> Result<Longhands, ParseError<'i>> {
use crate::values::specified::box_::BreakBetween;
Ok(expanded! {
break_before: BreakBetween::parse_legacy(input)?,
})
}
impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
self.break_before.to_css_legacy(dest)
}
}
</%helpers:shorthand>
<%helpers:shorthand
name="page-break-after"
products="gecko"
flags="SHORTHAND_IN_GETCS IS_LEGACY_SHORTHAND"
sub_properties="break-after"
spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-after"
>
pub fn parse_value<'i>(
_: &ParserContext,
input: &mut Parser<'i, '_>,
) -> Result<Longhands, ParseError<'i>> {
use crate::values::specified::box_::BreakBetween;
Ok(expanded! {
break_after: BreakBetween::parse_legacy(input)?,
})
}
impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
self.break_after.to_css_legacy(dest)
}
}
</%helpers:shorthand>

View file

@ -453,6 +453,7 @@ impl RuleTree {
StyleSource::from_declarations(pdb.clone_arc()),
level,
);
*important_rules_changed = true;
}
} else {
if pdb.read_with(level.guard(guards)).any_normal() {

View file

@ -14,6 +14,7 @@ use crate::values::computed::length::CalcLengthOrPercentage;
use crate::values::computed::url::ComputedUrl;
use crate::values::computed::Angle as ComputedAngle;
use crate::values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
use crate::values::CSSFloat;
use euclid::{Point2D, Size2D};
use smallvec::SmallVec;
use std::cmp;
@ -23,6 +24,7 @@ pub mod effects;
mod font;
mod length;
mod svg;
pub mod transform;
/// The category a property falls into for ordering purposes.
///
@ -86,6 +88,15 @@ pub fn compare_property_priority(a: &PropertyId, b: &PropertyId) -> cmp::Orderin
.then_with(|| a.idl_name_sort_order().cmp(&b.idl_name_sort_order()))
}
/// A helper function to animate two multiplicative factor.
pub fn animate_multiplicative_factor(
this: CSSFloat,
other: CSSFloat,
procedure: Procedure,
) -> Result<CSSFloat, ()> {
Ok((this - 1.).animate(&(other - 1.), procedure)? + 1.)
}
/// Animate from one value to another.
///
/// This trait is derivable with `#[derive(Animate)]`. The derived

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,7 @@
//! Computed types for CSS values that are related to transformations.
use super::CSSFloat;
use crate::values::animated::transform::{Perspective, Scale3D, Translate3D};
use crate::values::animated::ToAnimatedZero;
use crate::values::computed::{Angle, Integer, Length, LengthOrPercentage, Number, Percentage};
use crate::values::generics::transform as generic;
@ -47,8 +48,8 @@ pub type Matrix = generic::Matrix<Number>;
// matrices instead of being split across lines
#[cfg_attr(rustfmt, rustfmt_skip)]
impl Matrix3D {
#[inline]
/// Get an identity matrix
#[inline]
pub fn identity() -> Self {
Self {
m11: 1.0, m12: 0.0, m13: 0.0, m14: 0.0,
@ -59,6 +60,7 @@ impl Matrix3D {
}
/// Convert to a 2D Matrix
#[inline]
pub fn into_2d(self) -> Result<Matrix, ()> {
if self.m13 == 0. && self.m23 == 0. &&
self.m31 == 0. && self.m32 == 0. &&
@ -73,6 +75,253 @@ impl Matrix3D {
Err(())
}
}
/// Return true if this has 3D components.
#[inline]
pub fn is_3d(&self) -> bool {
self.m13 != 0.0 || self.m14 != 0.0 ||
self.m23 != 0.0 || self.m24 != 0.0 ||
self.m31 != 0.0 || self.m32 != 0.0 ||
self.m33 != 1.0 || self.m34 != 0.0 ||
self.m43 != 0.0 || self.m44 != 1.0
}
/// Return determinant value.
#[inline]
pub fn determinant(&self) -> CSSFloat {
self.m14 * self.m23 * self.m32 * self.m41 -
self.m13 * self.m24 * self.m32 * self.m41 -
self.m14 * self.m22 * self.m33 * self.m41 +
self.m12 * self.m24 * self.m33 * self.m41 +
self.m13 * self.m22 * self.m34 * self.m41 -
self.m12 * self.m23 * self.m34 * self.m41 -
self.m14 * self.m23 * self.m31 * self.m42 +
self.m13 * self.m24 * self.m31 * self.m42 +
self.m14 * self.m21 * self.m33 * self.m42 -
self.m11 * self.m24 * self.m33 * self.m42 -
self.m13 * self.m21 * self.m34 * self.m42 +
self.m11 * self.m23 * self.m34 * self.m42 +
self.m14 * self.m22 * self.m31 * self.m43 -
self.m12 * self.m24 * self.m31 * self.m43 -
self.m14 * self.m21 * self.m32 * self.m43 +
self.m11 * self.m24 * self.m32 * self.m43 +
self.m12 * self.m21 * self.m34 * self.m43 -
self.m11 * self.m22 * self.m34 * self.m43 -
self.m13 * self.m22 * self.m31 * self.m44 +
self.m12 * self.m23 * self.m31 * self.m44 +
self.m13 * self.m21 * self.m32 * self.m44 -
self.m11 * self.m23 * self.m32 * self.m44 -
self.m12 * self.m21 * self.m33 * self.m44 +
self.m11 * self.m22 * self.m33 * self.m44
}
/// Transpose a matrix.
#[inline]
pub fn transpose(&self) -> Self {
Self {
m11: self.m11, m12: self.m21, m13: self.m31, m14: self.m41,
m21: self.m12, m22: self.m22, m23: self.m32, m24: self.m42,
m31: self.m13, m32: self.m23, m33: self.m33, m34: self.m43,
m41: self.m14, m42: self.m24, m43: self.m34, m44: self.m44,
}
}
/// Return inverse matrix.
pub fn inverse(&self) -> Result<Matrix3D, ()> {
let mut det = self.determinant();
if det == 0.0 {
return Err(());
}
det = 1.0 / det;
let x = Matrix3D {
m11: det *
(self.m23 * self.m34 * self.m42 - self.m24 * self.m33 * self.m42 +
self.m24 * self.m32 * self.m43 - self.m22 * self.m34 * self.m43 -
self.m23 * self.m32 * self.m44 + self.m22 * self.m33 * self.m44),
m12: det *
(self.m14 * self.m33 * self.m42 - self.m13 * self.m34 * self.m42 -
self.m14 * self.m32 * self.m43 + self.m12 * self.m34 * self.m43 +
self.m13 * self.m32 * self.m44 - self.m12 * self.m33 * self.m44),
m13: det *
(self.m13 * self.m24 * self.m42 - self.m14 * self.m23 * self.m42 +
self.m14 * self.m22 * self.m43 - self.m12 * self.m24 * self.m43 -
self.m13 * self.m22 * self.m44 + self.m12 * self.m23 * self.m44),
m14: det *
(self.m14 * self.m23 * self.m32 - self.m13 * self.m24 * self.m32 -
self.m14 * self.m22 * self.m33 + self.m12 * self.m24 * self.m33 +
self.m13 * self.m22 * self.m34 - self.m12 * self.m23 * self.m34),
m21: det *
(self.m24 * self.m33 * self.m41 - self.m23 * self.m34 * self.m41 -
self.m24 * self.m31 * self.m43 + self.m21 * self.m34 * self.m43 +
self.m23 * self.m31 * self.m44 - self.m21 * self.m33 * self.m44),
m22: det *
(self.m13 * self.m34 * self.m41 - self.m14 * self.m33 * self.m41 +
self.m14 * self.m31 * self.m43 - self.m11 * self.m34 * self.m43 -
self.m13 * self.m31 * self.m44 + self.m11 * self.m33 * self.m44),
m23: det *
(self.m14 * self.m23 * self.m41 - self.m13 * self.m24 * self.m41 -
self.m14 * self.m21 * self.m43 + self.m11 * self.m24 * self.m43 +
self.m13 * self.m21 * self.m44 - self.m11 * self.m23 * self.m44),
m24: det *
(self.m13 * self.m24 * self.m31 - self.m14 * self.m23 * self.m31 +
self.m14 * self.m21 * self.m33 - self.m11 * self.m24 * self.m33 -
self.m13 * self.m21 * self.m34 + self.m11 * self.m23 * self.m34),
m31: det *
(self.m22 * self.m34 * self.m41 - self.m24 * self.m32 * self.m41 +
self.m24 * self.m31 * self.m42 - self.m21 * self.m34 * self.m42 -
self.m22 * self.m31 * self.m44 + self.m21 * self.m32 * self.m44),
m32: det *
(self.m14 * self.m32 * self.m41 - self.m12 * self.m34 * self.m41 -
self.m14 * self.m31 * self.m42 + self.m11 * self.m34 * self.m42 +
self.m12 * self.m31 * self.m44 - self.m11 * self.m32 * self.m44),
m33: det *
(self.m12 * self.m24 * self.m41 - self.m14 * self.m22 * self.m41 +
self.m14 * self.m21 * self.m42 - self.m11 * self.m24 * self.m42 -
self.m12 * self.m21 * self.m44 + self.m11 * self.m22 * self.m44),
m34: det *
(self.m14 * self.m22 * self.m31 - self.m12 * self.m24 * self.m31 -
self.m14 * self.m21 * self.m32 + self.m11 * self.m24 * self.m32 +
self.m12 * self.m21 * self.m34 - self.m11 * self.m22 * self.m34),
m41: det *
(self.m23 * self.m32 * self.m41 - self.m22 * self.m33 * self.m41 -
self.m23 * self.m31 * self.m42 + self.m21 * self.m33 * self.m42 +
self.m22 * self.m31 * self.m43 - self.m21 * self.m32 * self.m43),
m42: det *
(self.m12 * self.m33 * self.m41 - self.m13 * self.m32 * self.m41 +
self.m13 * self.m31 * self.m42 - self.m11 * self.m33 * self.m42 -
self.m12 * self.m31 * self.m43 + self.m11 * self.m32 * self.m43),
m43: det *
(self.m13 * self.m22 * self.m41 - self.m12 * self.m23 * self.m41 -
self.m13 * self.m21 * self.m42 + self.m11 * self.m23 * self.m42 +
self.m12 * self.m21 * self.m43 - self.m11 * self.m22 * self.m43),
m44: det *
(self.m12 * self.m23 * self.m31 - self.m13 * self.m22 * self.m31 +
self.m13 * self.m21 * self.m32 - self.m11 * self.m23 * self.m32 -
self.m12 * self.m21 * self.m33 + self.m11 * self.m22 * self.m33),
};
Ok(x)
}
/// Multiply `pin * self`.
#[inline]
pub fn pre_mul_point4(&self, pin: &[f32; 4]) -> [f32; 4] {
[
pin[0] * self.m11 + pin[1] * self.m21 + pin[2] * self.m31 + pin[3] * self.m41,
pin[0] * self.m12 + pin[1] * self.m22 + pin[2] * self.m32 + pin[3] * self.m42,
pin[0] * self.m13 + pin[1] * self.m23 + pin[2] * self.m33 + pin[3] * self.m43,
pin[0] * self.m14 + pin[1] * self.m24 + pin[2] * self.m34 + pin[3] * self.m44,
]
}
/// Return the multiplication of two 4x4 matrices.
#[inline]
pub fn multiply(&self, other: &Self) -> Self {
Matrix3D {
m11: self.m11 * other.m11 + self.m12 * other.m21 +
self.m13 * other.m31 + self.m14 * other.m41,
m12: self.m11 * other.m12 + self.m12 * other.m22 +
self.m13 * other.m32 + self.m14 * other.m42,
m13: self.m11 * other.m13 + self.m12 * other.m23 +
self.m13 * other.m33 + self.m14 * other.m43,
m14: self.m11 * other.m14 + self.m12 * other.m24 +
self.m13 * other.m34 + self.m14 * other.m44,
m21: self.m21 * other.m11 + self.m22 * other.m21 +
self.m23 * other.m31 + self.m24 * other.m41,
m22: self.m21 * other.m12 + self.m22 * other.m22 +
self.m23 * other.m32 + self.m24 * other.m42,
m23: self.m21 * other.m13 + self.m22 * other.m23 +
self.m23 * other.m33 + self.m24 * other.m43,
m24: self.m21 * other.m14 + self.m22 * other.m24 +
self.m23 * other.m34 + self.m24 * other.m44,
m31: self.m31 * other.m11 + self.m32 * other.m21 +
self.m33 * other.m31 + self.m34 * other.m41,
m32: self.m31 * other.m12 + self.m32 * other.m22 +
self.m33 * other.m32 + self.m34 * other.m42,
m33: self.m31 * other.m13 + self.m32 * other.m23 +
self.m33 * other.m33 + self.m34 * other.m43,
m34: self.m31 * other.m14 + self.m32 * other.m24 +
self.m33 * other.m34 + self.m34 * other.m44,
m41: self.m41 * other.m11 + self.m42 * other.m21 +
self.m43 * other.m31 + self.m44 * other.m41,
m42: self.m41 * other.m12 + self.m42 * other.m22 +
self.m43 * other.m32 + self.m44 * other.m42,
m43: self.m41 * other.m13 + self.m42 * other.m23 +
self.m43 * other.m33 + self.m44 * other.m43,
m44: self.m41 * other.m14 + self.m42 * other.m24 +
self.m43 * other.m34 + self.m44 * other.m44,
}
}
/// Scale the matrix by a factor.
#[inline]
pub fn scale_by_factor(&mut self, scaling_factor: CSSFloat) {
self.m11 *= scaling_factor;
self.m12 *= scaling_factor;
self.m13 *= scaling_factor;
self.m14 *= scaling_factor;
self.m21 *= scaling_factor;
self.m22 *= scaling_factor;
self.m23 *= scaling_factor;
self.m24 *= scaling_factor;
self.m31 *= scaling_factor;
self.m32 *= scaling_factor;
self.m33 *= scaling_factor;
self.m34 *= scaling_factor;
self.m41 *= scaling_factor;
self.m42 *= scaling_factor;
self.m43 *= scaling_factor;
self.m44 *= scaling_factor;
}
/// Return the matrix 3x3 part (top-left corner).
/// This is used by retrieving the scale and shear factors
/// during decomposing a 3d matrix.
#[inline]
pub fn get_matrix_3x3_part(&self) -> [[f32; 3]; 3] {
[
[ self.m11, self.m12, self.m13 ],
[ self.m21, self.m22, self.m23 ],
[ self.m31, self.m32, self.m33 ],
]
}
/// Set perspective on the matrix.
#[inline]
pub fn set_perspective(&mut self, perspective: &Perspective) {
self.m14 = perspective.0;
self.m24 = perspective.1;
self.m34 = perspective.2;
self.m44 = perspective.3;
}
/// Apply translate on the matrix.
#[inline]
pub fn apply_translate(&mut self, translate: &Translate3D) {
self.m41 += translate.0 * self.m11 + translate.1 * self.m21 + translate.2 * self.m31;
self.m42 += translate.0 * self.m12 + translate.1 * self.m22 + translate.2 * self.m32;
self.m43 += translate.0 * self.m13 + translate.1 * self.m23 + translate.2 * self.m33;
self.m44 += translate.0 * self.m14 + translate.1 * self.m24 + translate.2 * self.m34;
}
/// Apply scale on the matrix.
#[inline]
pub fn apply_scale(&mut self, scale: &Scale3D) {
self.m11 *= scale.0;
self.m12 *= scale.0;
self.m13 *= scale.0;
self.m14 *= scale.0;
self.m21 *= scale.1;
self.m22 *= scale.1;
self.m23 *= scale.1;
self.m24 *= scale.1;
self.m31 *= scale.2;
self.m32 *= scale.2;
self.m33 *= scale.2;
self.m34 *= scale.2;
}
}
#[cfg_attr(rustfmt, rustfmt_skip)]

View file

@ -529,15 +529,7 @@ pub fn get_normalized_vector_and_angle<T: Zero>(
}
#[derive(
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedZero,
ToComputedValue,
Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue,
)]
/// A value of the `Rotate` property
///
@ -599,15 +591,7 @@ where
}
#[derive(
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedZero,
ToComputedValue,
Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue,
)]
/// A value of the `Scale` property
///
@ -648,14 +632,7 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
}
#[derive(
Clone,
ComputeSquaredDistance,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedZero,
ToComputedValue,
Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue,
)]
/// A value of the `Translate` property
///

View file

@ -19,6 +19,48 @@ use cssparser::Parser;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss};
/// A specified value for a single side of a `border-style` property.
///
/// The order here corresponds to the integer values from the border conflict
/// resolution rules in CSS 2.1 § 17.6.2.1. Higher values override lower values.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
Clone,
Copy,
Debug,
Eq,
MallocSizeOf,
Ord,
Parse,
PartialEq,
PartialOrd,
SpecifiedValueInfo,
ToComputedValue,
ToCss,
)]
#[repr(u8)]
pub enum BorderStyle {
Hidden,
None,
Inset,
Groove,
Outset,
Ridge,
Dotted,
Dashed,
Solid,
Double,
}
impl BorderStyle {
/// Whether this border style is either none or hidden.
#[inline]
pub fn none_or_hidden(&self) -> bool {
matches!(*self, BorderStyle::None | BorderStyle::Hidden)
}
}
/// A specified value for a single side of the `border-width` property.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
pub enum BorderSideWidth {

View file

@ -178,30 +178,6 @@ impl Display {
}
}
/// Whether `new_display` should be ignored, given a previous
/// `old_display` value.
///
/// This is used to ignore `display: -moz-box` declarations after an
/// equivalent `display: -webkit-box` declaration, since the former
/// has a vastly different meaning. See bug 1107378 and bug 1407701.
///
/// FIXME(emilio): This is a pretty decent hack, we should try to
/// remove it.
pub fn should_ignore_parsed_value(_old_display: Self, _new_display: Self) -> bool {
#[cfg(feature = "gecko")]
{
match (_old_display, _new_display) {
(Display::WebkitBox, Display::MozBox) |
(Display::WebkitInlineBox, Display::MozInlineBox) => {
return true;
},
_ => {},
}
}
return false;
}
/// Returns whether this "display" value is one of the types for
/// ruby.
#[cfg(feature = "gecko")]
@ -1155,10 +1131,11 @@ pub enum Appearance {
TabScrollArrowBack,
#[parse(condition = "in_ua_or_chrome_sheet")]
TabScrollArrowForward,
/// A textfield or text area.
/// A multi-line text field, e.g. HTML <textarea>.
#[parse(aliases = "textfield-multiline")]
Textarea,
/// A single-line text field, e.g. HTML <input type=text>.
Textfield,
/// A multiline text field.
TextfieldMultiline,
/// A toolbar in an application window.
#[parse(condition = "in_ua_or_chrome_sheet")]
Toolbar,
@ -1309,13 +1286,58 @@ pub enum Appearance {
)]
#[repr(u8)]
pub enum BreakBetween {
Auto,
Always,
Auto,
Page,
Avoid,
Left,
Right,
}
impl BreakBetween {
/// Parse a legacy break-between value for `page-break-*`.
///
/// See https://drafts.csswg.org/css-break/#page-break-properties.
#[inline]
pub fn parse_legacy<'i>(input: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
let location = input.current_source_location();
let ident = input.expect_ident()?;
let break_value = match BreakBetween::from_ident(ident) {
Ok(v) => v,
Err(()) => {
return Err(location
.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())))
},
};
match break_value {
BreakBetween::Always => Ok(BreakBetween::Page),
BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
Ok(break_value)
},
BreakBetween::Page => {
Err(location
.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())))
},
}
}
/// Serialize a legacy break-between value for `page-break-*`.
///
/// See https://drafts.csswg.org/css-break/#page-break-properties.
pub fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
match *self {
BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
self.to_css(dest)
},
BreakBetween::Page => dest.write_str("always"),
BreakBetween::Always => Ok(()),
}
}
}
/// A kind of break within a box.
///
/// https://drafts.csswg.org/css-break/#break-within

View file

@ -34,7 +34,7 @@ pub use self::background::{BackgroundRepeat, BackgroundSize};
pub use self::basic_shape::FillRule;
pub use self::border::{BorderCornerRadius, BorderImageSlice, BorderImageWidth};
pub use self::border::{BorderImageRepeat, BorderImageSideWidth};
pub use self::border::{BorderRadius, BorderSideWidth, BorderSpacing};
pub use self::border::{BorderRadius, BorderSideWidth, BorderSpacing, BorderStyle};
pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display};
pub use self::box_::{Appearance, BreakBetween, BreakWithin, Clear, Float};
pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective, Resize};
@ -152,46 +152,6 @@ fn parse_number_with_clamping_mode<'i, 't>(
})
}
// The integer values here correspond to the border conflict resolution rules in CSS 2.1 §
// 17.6.2.1. Higher values override lower values.
//
// FIXME(emilio): Should move to border.rs
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
Clone,
Copy,
Debug,
Eq,
MallocSizeOf,
Ord,
Parse,
PartialEq,
PartialOrd,
SpecifiedValueInfo,
ToComputedValue,
ToCss,
)]
pub enum BorderStyle {
None = -1,
Solid = 6,
Double = 7,
Dotted = 4,
Dashed = 5,
Hidden = -2,
Groove = 1,
Ridge = 3,
Inset = 0,
Outset = 2,
}
impl BorderStyle {
/// Whether this border style is either none or hidden.
pub fn none_or_hidden(&self) -> bool {
matches!(*self, BorderStyle::None | BorderStyle::Hidden)
}
}
/// A CSS `<number>` specified value.
///
/// https://drafts.csswg.org/css-values-3/#number-value

View file

@ -23,19 +23,20 @@ use style_traits::ParseError;
ToComputedValue,
ToCss,
)]
#[repr(C, u8)]
/// <https://drafts.csswg.org/css-ui/#propdef-outline-style>
pub enum OutlineStyle {
/// auto
Auto,
/// <border-style>
Other(BorderStyle),
BorderStyle(BorderStyle),
}
impl OutlineStyle {
#[inline]
/// Get default value as None
pub fn none() -> OutlineStyle {
OutlineStyle::Other(BorderStyle::None)
OutlineStyle::BorderStyle(BorderStyle::None)
}
#[inline]
@ -43,7 +44,7 @@ impl OutlineStyle {
pub fn none_or_hidden(&self) -> bool {
match *self {
OutlineStyle::Auto => false,
OutlineStyle::Other(ref border_style) => border_style.none_or_hidden(),
OutlineStyle::BorderStyle(ref style) => style.none_or_hidden(),
}
}
}
@ -59,7 +60,7 @@ impl Parse for OutlineStyle {
.new_custom_error(SelectorParseErrorKind::UnexpectedIdent("hidden".into())));
}
return Ok(OutlineStyle::Other(border_style));
return Ok(OutlineStyle::BorderStyle(border_style));
}
input.expect_ident_matching("auto")?;

View file

@ -141,11 +141,6 @@ impl Parse for ScrollbarColor {
}
}
fn in_ua_sheet(context: &ParserContext) -> bool {
use crate::stylesheets::Origin;
context.stylesheet_origin == Origin::UserAgent
}
/// The specified value for the `user-select` property.
///
/// https://drafts.csswg.org/css-ui-4/#propdef-user-select
@ -168,15 +163,6 @@ pub enum UserSelect {
Text,
#[parse(aliases = "-moz-none")]
None,
/// Force selection of all children, unless an ancestor has `none` set.
/// Force selection of all children.
All,
/// Like `text`, except that it won't get overridden by ancestors having
/// `all`.
///
/// FIXME(emilio): This only has one use in contenteditable.css, can we find
/// a better way to do this?
///
/// See bug 1181130.
#[parse(condition = "in_ua_sheet")]
MozText,
}

View file

@ -1,2 +0,0 @@
[variable-exponential-blowup.html]
expected: TIMEOUT