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

style: Sync changes from mozilla-central.

See each individual commit for details.

https://bugzilla.mozilla.org/show_bug.cgi?id=1488172

<!-- 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/21588)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-09-03 08:12:22 -04:00 committed by GitHub
commit d8446f85a9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
68 changed files with 2673 additions and 1363 deletions

View file

@ -36,6 +36,7 @@ invalid
keydown
keypress
left
ltr
load
loadeddata
loadedmetadata
@ -65,6 +66,7 @@ readystatechange
reftest-wait
reset
right
rtl
sans-serif
scan
screen

View file

@ -70,7 +70,7 @@ use style::dom::{TDocument, TElement, TNode, TShadowRoot};
use style::element_state::*;
use style::font_metrics::ServoMetricsProvider;
use style::properties::{ComputedValues, PropertyDeclarationBlock};
use style::selector_parser::{AttrValue as SelectorAttrValue, NonTSPseudoClass, PseudoClassStringArg};
use style::selector_parser::{AttrValue as SelectorAttrValue, NonTSPseudoClass, Lang};
use style::selector_parser::{PseudoElement, SelectorImpl, extended_filtering};
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
use style::str::is_whitespace;
@ -168,7 +168,7 @@ impl<'lr> TShadowRoot for ShadowRoot<'lr> {
match self.0 { }
}
fn style_data<'a>(&self) -> &'a CascadeData
fn style_data<'a>(&self) -> Option<&'a CascadeData>
where
Self: 'a,
{
@ -531,7 +531,7 @@ impl<'le> TElement for ServoLayoutElement<'le> {
fn match_element_lang(
&self,
override_lang: Option<Option<SelectorAttrValue>>,
value: &PseudoClassStringArg,
value: &Lang,
) -> bool {
// Servo supports :lang() from CSS Selectors 4, which can take a comma-
// separated list of language tags in the pseudo-class, and which

View file

@ -845,8 +845,8 @@ macro_rules! malloc_size_of_is_0(
);
malloc_size_of_is_0!(bool, char, str);
malloc_size_of_is_0!(u8, u16, u32, u64, usize);
malloc_size_of_is_0!(i8, i16, i32, i64, isize);
malloc_size_of_is_0!(u8, u16, u32, u64, u128, usize);
malloc_size_of_is_0!(i8, i16, i32, i64, i128, isize);
malloc_size_of_is_0!(f32, f64);
malloc_size_of_is_0!(std::sync::atomic::AtomicBool);

View file

@ -44,6 +44,7 @@ impl CSS {
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
decl.eval(&context)
}
@ -61,6 +62,7 @@ impl CSS {
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
cond.eval(&context)
} else {

View file

@ -81,6 +81,7 @@ impl CSSMediaRule {
ParsingMode::DEFAULT,
quirks_mode,
window.css_error_reporter(),
None,
);
let new_medialist = StyleMediaList::parse(&context, &mut input);

View file

@ -69,6 +69,7 @@ impl CSSSupportsRule {
ParsingMode::DEFAULT,
quirks_mode,
None,
None,
);
let enabled = cond.eval(&context);
let mut guard = self.cssconditionrule.shared_lock().write();

View file

@ -538,12 +538,17 @@ impl HTMLImageElement {
/// https://html.spec.whatwg.org/multipage/#matches-the-environment
fn matches_environment(&self, media_query: String) -> bool {
let document = document_from_node(self);
let device = document.device();
if !device.is_some() {
return false;
}
let device = match document.device() {
Some(device) => device,
None => return false,
};
let quirks_mode = document.quirks_mode();
let document_url = &document.url();
// FIXME(emilio): This should do the same that we do for other media
// lists regarding the rule type and such, though it doesn't really
// matter right now...
//
// Also, ParsingMode::all() is wrong, and should be DEFAULT.
let context = ParserContext::new(
Origin::Author,
document_url,
@ -551,11 +556,12 @@ impl HTMLImageElement {
ParsingMode::all(),
quirks_mode,
None,
None,
);
let mut parserInput = ParserInput::new(&media_query);
let mut parser = Parser::new(&mut parserInput);
let media_list = MediaList::parse(&context, &mut parser);
media_list.evaluate(&device.unwrap(), quirks_mode)
media_list.evaluate(&device, quirks_mode)
}
/// <https://html.spec.whatwg.org/multipage/#normalise-the-source-densities>
@ -1039,9 +1045,12 @@ pub fn parse_a_sizes_attribute(value: DOMString) -> SourceSizeList {
Origin::Author,
&url,
Some(CssRuleType::Style),
// FIXME(emilio): why ::empty() instead of ::DEFAULT? Also, what do
// browsers do regarding quirks-mode in a media list?
ParsingMode::empty(),
QuirksMode::NoQuirks,
None,
None,
);
SourceSizeList::parse(&context, &mut parser)
}

View file

@ -287,6 +287,7 @@ impl HTMLLinkElement {
ParsingMode::DEFAULT,
document.quirks_mode(),
window.css_error_reporter(),
None,
);
let media = MediaList::parse(&context, &mut css_parser);

View file

@ -91,6 +91,7 @@ impl HTMLStyleElement {
ParsingMode::DEFAULT,
doc.quirks_mode(),
css_error_reporter,
None,
);
let shared_lock = node.owner_doc().style_shared_lock().clone();
let mut input = ParserInput::new(&mq_str);

View file

@ -83,6 +83,7 @@ impl MediaListMethods for MediaList {
ParsingMode::DEFAULT,
quirks_mode,
window.css_error_reporter(),
None,
);
*media_queries = StyleMediaList::parse(&context, &mut parser);
}
@ -123,6 +124,7 @@ impl MediaListMethods for MediaList {
ParsingMode::DEFAULT,
quirks_mode,
win.css_error_reporter(),
None,
);
let m = MediaQuery::parse(&context, &mut parser);
// Step 2
@ -156,6 +158,7 @@ impl MediaListMethods for MediaList {
ParsingMode::DEFAULT,
quirks_mode,
win.css_error_reporter(),
None,
);
let m = MediaQuery::parse(&context, &mut parser);
// Step 2

View file

@ -1089,6 +1089,7 @@ impl WindowMethods for Window {
ParsingMode::DEFAULT,
quirks_mode,
self.css_error_reporter(),
None,
);
let media_query_list =
media_queries::MediaList::parse(&context, &mut parser);

View file

@ -406,11 +406,7 @@ mod bindings {
fn generate_structs() {
let builder = Builder::get_initial_builder()
.enable_cxx_namespaces()
.with_codegen_config(CodegenConfig {
types: true,
vars: true,
..CodegenConfig::nothing()
});
.with_codegen_config(CodegenConfig::TYPES | CodegenConfig::VARS);
let mut fixups = vec![];
let builder = BuilderWithConfig::new(builder, CONFIG["structs"].as_table().unwrap())
.handle_common(&mut fixups)
@ -500,10 +496,7 @@ mod bindings {
fn generate_bindings() {
let builder = Builder::get_initial_builder()
.disable_name_namespacing()
.with_codegen_config(CodegenConfig {
functions: true,
..CodegenConfig::nothing()
});
.with_codegen_config(CodegenConfig::FUNCTIONS);
let config = CONFIG["bindings"].as_table().unwrap();
let mut structs_types = HashSet::new();
let mut fixups = vec![];

View file

@ -7,6 +7,7 @@ autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated usi
* a. Alternatively, you can clone `https://github.com/eqrion/cbindgen` and use a tagged release
* 2. Run `rustup run nightly cbindgen toolkit/library/rust/ --lockfile Cargo.lock --crate style -o layout/style/ServoStyleConsts.h`
*/"""
include_guard = "mozilla_ServoStyleConsts_h"
include_version = true
braces = "SameLine"
line_length = 80
@ -22,5 +23,11 @@ derive_helper_methods = true
[export]
prefix = "Style"
include = ["StyleDisplay", "StyleAppearance", "StyleDisplayMode"]
item_types = ["enums"]
include = [
"StyleAppearance",
"StyleDisplay",
"StyleDisplayMode",
"StyleFillRule",
"StylePathCommand"
]
item_types = ["enums", "structs", "typedefs"]

View file

@ -19,7 +19,7 @@ use element_state::ElementState;
use font_metrics::FontMetricsProvider;
use media_queries::Device;
use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
use selector_parser::{AttrValue, PseudoClassStringArg, PseudoElement, SelectorImpl};
use selector_parser::{AttrValue, Lang, PseudoElement, SelectorImpl};
use selectors::Element as SelectorsElement;
use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode};
use selectors::sink::Push;
@ -342,7 +342,7 @@ pub trait TShadowRoot: Sized + Copy + Clone + PartialEq {
fn host(&self) -> <Self::ConcreteNode as TNode>::ConcreteElement;
/// Get the style data for this ShadowRoot.
fn style_data<'a>(&self) -> &'a CascadeData
fn style_data<'a>(&self) -> Option<&'a CascadeData>
where
Self: 'a;
@ -824,30 +824,36 @@ pub trait TElement:
if let Some(shadow) = self.containing_shadow() {
doc_rules_apply = false;
f(
shadow.style_data(),
self.as_node().owner_doc().quirks_mode(),
Some(shadow.host()),
);
if let Some(data) = shadow.style_data() {
f(
data,
self.as_node().owner_doc().quirks_mode(),
Some(shadow.host()),
);
}
}
if let Some(shadow) = self.shadow_root() {
f(
shadow.style_data(),
self.as_node().owner_doc().quirks_mode(),
Some(shadow.host()),
);
if let Some(data) = shadow.style_data() {
f(
data,
self.as_node().owner_doc().quirks_mode(),
Some(shadow.host()),
);
}
}
let mut current = self.assigned_slot();
while let Some(slot) = current {
// Slots can only have assigned nodes when in a shadow tree.
let shadow = slot.containing_shadow().unwrap();
f(
shadow.style_data(),
self.as_node().owner_doc().quirks_mode(),
Some(shadow.host()),
);
if let Some(data) = shadow.style_data() {
f(
data,
self.as_node().owner_doc().quirks_mode(),
Some(shadow.host()),
);
}
current = slot.assigned_slot();
}
@ -889,7 +895,7 @@ pub trait TElement:
fn match_element_lang(
&self,
override_lang: Option<Option<AttrValue>>,
value: &PseudoClassStringArg,
value: &Lang,
) -> bool;
/// Returns whether this element is the main body element of the HTML

View file

@ -19,6 +19,7 @@ use stylesheets::{Origin, RulesMutateError};
use values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image};
use values::computed::{Integer, LengthOrPercentage, LengthOrPercentageOrAuto};
use values::computed::{Percentage, TextAlign};
use values::computed::image::LineDirection;
use values::computed::url::ComputedImageUrl;
use values::generics::box_::VerticalAlign;
use values::generics::grid::{TrackListValue, TrackSize};
@ -139,6 +140,68 @@ impl Angle {
}
}
fn line_direction(
horizontal: LengthOrPercentage,
vertical: LengthOrPercentage,
) -> LineDirection {
use values::computed::position::Position;
use values::specified::position::{X, Y};
let horizontal_percentage = match horizontal {
LengthOrPercentage::Percentage(percentage) => Some(percentage.0),
_ => None,
};
let vertical_percentage = match vertical {
LengthOrPercentage::Percentage(percentage) => Some(percentage.0),
_ => None,
};
let horizontal_as_corner = horizontal_percentage.and_then(|percentage| {
if percentage == 0.0 {
Some(X::Left)
} else if percentage == 1.0 {
Some(X::Right)
} else {
None
}
});
let vertical_as_corner = vertical_percentage.and_then(|percentage| {
if percentage == 0.0 {
Some(Y::Top)
} else if percentage == 1.0 {
Some(Y::Bottom)
} else {
None
}
});
if let (Some(hc), Some(vc)) = (horizontal_as_corner, vertical_as_corner) {
return LineDirection::Corner(hc, vc)
}
if let Some(hc) = horizontal_as_corner {
if vertical_percentage == Some(0.5) {
return LineDirection::Horizontal(hc)
}
}
if let Some(vc) = vertical_as_corner {
if horizontal_percentage == Some(0.5) {
return LineDirection::Vertical(vc)
}
}
LineDirection::MozPosition(
Some(Position {
horizontal,
vertical,
}),
None,
)
}
impl nsStyleImage {
/// Set a given Servo `Image` value into this `nsStyleImage`.
pub fn set(&mut self, image: Image) {
@ -174,13 +237,13 @@ impl nsStyleImage {
}
}
// FIXME(emilio): This is really complex, we should use cbindgen for this.
fn set_gradient(&mut self, gradient: Gradient) {
use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER as CLOSEST_CORNER;
use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE;
use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER;
use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE;
use self::structs::nsStyleCoord;
use values::computed::image::LineDirection;
use values::generics::image::{Circle, Ellipse, EndingShape, GradientKind, ShapeExtent};
use values::specified::position::{X, Y};
@ -437,12 +500,11 @@ impl nsStyleImage {
use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE;
use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER;
use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE;
use values::computed::{Length, LengthOrPercentage};
use values::computed::Length;
use values::computed::image::LineDirection;
use values::computed::position::Position;
use values::generics::image::{Circle, ColorStop, CompatMode, Ellipse};
use values::generics::image::{EndingShape, GradientKind, ShapeExtent};
use values::specified::position::{X, Y};
let gecko_gradient = bindings::Gecko_GetGradientImageValue(self)
.as_ref()
@ -456,41 +518,7 @@ impl nsStyleImage {
let line_direction = match (angle, horizontal_style, vertical_style) {
(Some(a), None, None) => LineDirection::Angle(a),
(None, Some(horizontal), Some(vertical)) => {
let horizontal_as_corner = match horizontal {
LengthOrPercentage::Percentage(percentage) => {
if percentage.0 == 0.0 {
Some(X::Left)
} else if percentage.0 == 1.0 {
Some(X::Right)
} else {
None
}
},
_ => None,
};
let vertical_as_corner = match vertical {
LengthOrPercentage::Percentage(percentage) => {
if percentage.0 == 0.0 {
Some(Y::Top)
} else if percentage.0 == 1.0 {
Some(Y::Bottom)
} else {
None
}
},
_ => None,
};
match (horizontal_as_corner, vertical_as_corner) {
(Some(hc), Some(vc)) => LineDirection::Corner(hc, vc),
_ => LineDirection::MozPosition(
Some(Position {
horizontal,
vertical,
}),
None,
),
}
line_direction(horizontal, vertical)
},
(Some(_), Some(horizontal), Some(vertical)) => LineDirection::MozPosition(
Some(Position {
@ -638,13 +666,15 @@ pub mod basic_shape {
use values::computed::basic_shape::{BasicShape, ClippingShape, FloatAreaShape, ShapeRadius};
use values::computed::border::{BorderCornerRadius, BorderRadius};
use values::computed::length::LengthOrPercentage;
use values::computed::motion::OffsetPath;
use values::computed::position;
use values::computed::url::ComputedUrl;
use values::generics::basic_shape::{BasicShape as GenericBasicShape, InsetRect, Polygon};
use values::generics::basic_shape::{Circle, Ellipse, FillRule};
use values::generics::basic_shape::{Circle, Ellipse, FillRule, Path, PolygonCoord};
use values::generics::basic_shape::{GeometryBox, ShapeBox, ShapeSource};
use values::generics::border::BorderRadius as GenericBorderRadius;
use values::generics::rect::Rect;
use values::specified::SVGPathData;
impl StyleShapeSource {
/// Convert StyleShapeSource to ShapeSource except URL and Image
@ -669,6 +699,34 @@ pub mod basic_shape {
Some(ShapeSource::Shape(shape, reference_box))
},
StyleShapeSourceType::URL | StyleShapeSourceType::Image => None,
StyleShapeSourceType::Path => {
let path = self.to_svg_path().expect("expect an SVGPathData");
let gecko_path = unsafe { &*self.__bindgen_anon_1.mSVGPath.as_ref().mPtr };
let fill = if gecko_path.mFillRule == StyleFillRule::Evenodd {
FillRule::Evenodd
} else {
FillRule::Nonzero
};
Some(ShapeSource::Path(Path { fill, path }))
},
}
}
/// Generate a SVGPathData from StyleShapeSource if possible.
fn to_svg_path(&self) -> Option<SVGPathData> {
use gecko_bindings::structs::StylePathCommand;
use values::specified::svg_path::PathCommand;
match self.mType {
StyleShapeSourceType::Path => {
let gecko_path = unsafe { &*self.__bindgen_anon_1.mSVGPath.as_ref().mPtr };
let result: Vec<PathCommand> =
gecko_path.mPath.iter().map(|gecko: &StylePathCommand| {
// unsafe: cbindgen ensures the representation is the same.
unsafe { ::std::mem::transmute(*gecko) }
}).collect();
Some(SVGPathData::new(result.into_boxed_slice()))
},
_ => None,
}
}
}
@ -710,6 +768,21 @@ pub mod basic_shape {
}
}
impl<'a> From<&'a StyleShapeSource> for OffsetPath {
fn from(other: &'a StyleShapeSource) -> Self {
match other.mType {
StyleShapeSourceType::Path => {
OffsetPath::Path(other.to_svg_path().expect("Cannot convert to SVGPathData"))
},
StyleShapeSourceType::None => OffsetPath::none(),
StyleShapeSourceType::Shape |
StyleShapeSourceType::Box |
StyleShapeSourceType::URL |
StyleShapeSourceType::Image => unreachable!("Unsupported offset-path type"),
}
}
}
impl<'a> From<&'a StyleBasicShape> for BasicShape {
fn from(other: &'a StyleBasicShape) -> Self {
match other.mType {
@ -718,17 +791,15 @@ pub mod basic_shape {
let r = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[1]);
let b = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[2]);
let l = LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[3]);
let round = (&other.mRadius).into();
let round: BorderRadius = (&other.mRadius).into();
let round = if round.all_zero() { None } else { Some(round) };
let rect = Rect::new(
t.expect("inset() offset should be a length, percentage, or calc value"),
r.expect("inset() offset should be a length, percentage, or calc value"),
b.expect("inset() offset should be a length, percentage, or calc value"),
l.expect("inset() offset should be a length, percentage, or calc value"),
);
GenericBasicShape::Inset(InsetRect {
rect: rect,
round: Some(round),
})
GenericBasicShape::Inset(InsetRect { rect, round })
},
StyleBasicShapeType::Circle => GenericBasicShape::Circle(Circle {
radius: (&other.mCoordinates[0]).into(),
@ -749,11 +820,14 @@ pub mod basic_shape {
for i in 0..(other.mCoordinates.len() / 2) {
let x = 2 * i;
let y = x + 1;
coords.push((LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[x])
.expect("polygon() coordinate should be a length, percentage, or calc value"),
LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[y])
.expect("polygon() coordinate should be a length, percentage, or calc value")
))
coords.push(PolygonCoord(
LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[x])
.expect("polygon() coordinate should be a length, percentage, \
or calc value"),
LengthOrPercentage::from_gecko_style_coord(&other.mCoordinates[y])
.expect("polygon() coordinate should be a length, percentage, \
or calc value")
))
}
GenericBasicShape::Polygon(Polygon {
fill: fill_rule,

View file

@ -12,22 +12,13 @@
* Expected usage is as follows:
* ```
* macro_rules! pseudo_class_macro{
* (bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
* string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
* keyword: [$(($k_css:expr, $k_name:ident, $k_gecko_type:tt, $k_state:tt, $k_flags:tt),)*]) => {
* ([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => {
* // do stuff
* }
* }
* apply_non_ts_list!(pseudo_class_macro)
* ```
*
* The `string` and `keyword` variables will be applied to pseudoclasses that are of the form of
* functions with string or keyword arguments.
*
* Pending pseudo-classes:
*
* :scope -> <style scoped>, pending discussion.
*
* $gecko_type can be either "_" or an ident in Gecko's CSSPseudoClassType.
* $state can be either "_" or an expression of type ElementState. If present,
* the semantics are that the pseudo-class matches if any of the bits in
@ -39,7 +30,7 @@
macro_rules! apply_non_ts_list {
($apply_macro:ident) => {
$apply_macro! {
bare: [
[
("-moz-table-border-nonzero", MozTableBorderNonzero, mozTableBorderNonzero, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
("-moz-browser-frame", MozBrowserFrame, mozBrowserFrame, _, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME),
("link", Link, link, IN_UNVISITED_STATE, _),
@ -111,9 +102,6 @@ macro_rules! apply_non_ts_list {
("-moz-lwtheme-brighttext", MozLWThemeBrightText, mozLWThemeBrightText, _, _),
("-moz-lwtheme-darktext", MozLWThemeDarkText, mozLWThemeDarkText, _, _),
("-moz-window-inactive", MozWindowInactive, mozWindowInactive, _, _),
],
string: [
("lang", Lang, lang, _, _),
]
}
}

View file

@ -14,6 +14,7 @@ use properties::{ComputedValues, PropertyFlags};
use properties::longhands::display::computed_value::T as Display;
use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
use std::fmt;
use str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase};
use string_cache::Atom;
use thin_slice::ThinBoxedSlice;
use values::serialize_atom_identifier;

View file

@ -13,6 +13,9 @@ pub enum PseudoElement {
${pseudo.capitalized_pseudo()},
% endif
% endfor
/// ::-webkit-* that we don't recognize
/// https://github.com/whatwg/compat/issues/103
UnknownWebkit(Atom),
}
/// Important: If you change this, you should also update Gecko's
@ -47,11 +50,12 @@ PseudoElement::${pseudo.capitalized_pseudo()}${"({})".format(tree_arg) if pseudo
impl PseudoElement {
/// Get the pseudo-element as an atom.
#[inline]
pub fn atom(&self) -> Atom {
fn atom(&self) -> Atom {
match *self {
% for pseudo in PSEUDOS:
${pseudo_element_variant(pseudo)} => atom!("${pseudo.value}"),
% endfor
PseudoElement::UnknownWebkit(..) => unreachable!(),
}
}
@ -62,6 +66,7 @@ impl PseudoElement {
% for i, pseudo in enumerate(PSEUDOS):
${pseudo_element_variant(pseudo)} => ${i},
% endfor
PseudoElement::UnknownWebkit(..) => unreachable!(),
}
}
@ -105,6 +110,12 @@ impl PseudoElement {
}
}
/// Whether this pseudo-element is an unknown Webkit-prefixed pseudo-element.
#[inline]
pub fn is_unknown_webkit_pseudo_element(&self) -> bool {
matches!(*self, PseudoElement::UnknownWebkit(..))
}
/// Gets the flags associated to this pseudo-element, or 0 if it's an
/// anonymous box.
pub fn flags(&self) -> u32 {
@ -123,6 +134,7 @@ impl PseudoElement {
structs::SERVO_CSS_PSEUDO_ELEMENT_FLAGS_${pseudo.pseudo_ident},
% endif
% endfor
PseudoElement::UnknownWebkit(..) => 0,
}
}
@ -143,7 +155,7 @@ impl PseudoElement {
/// Construct a `CSSPseudoElementType` from a pseudo-element
#[inline]
pub fn pseudo_type(&self) -> CSSPseudoElementType {
fn pseudo_type(&self) -> CSSPseudoElementType {
use gecko_bindings::structs::CSSPseudoElementType_InheritingAnonBox;
match *self {
@ -158,6 +170,7 @@ impl PseudoElement {
PseudoElement::${pseudo.capitalized_pseudo()} => CSSPseudoElementType::NonInheritingAnonBox,
% endif
% endfor
PseudoElement::UnknownWebkit(..) => unreachable!(),
}
}
@ -242,11 +255,18 @@ impl PseudoElement {
return Some(PseudoElement::Placeholder);
}
_ => {
// FIXME: -moz-tree check should probably be
// ascii-case-insensitive.
if name.starts_with("-moz-tree-") {
if starts_with_ignore_ascii_case(name, "-moz-tree-") {
return PseudoElement::tree_pseudo_element(name, Box::new([]))
}
if unsafe {
structs::StaticPrefs_sVarCache_layout_css_unknown_webkit_pseudo_element
} {
const WEBKIT_PREFIX: &str = "-webkit-";
if starts_with_ignore_ascii_case(name, WEBKIT_PREFIX) {
let part = string_as_ascii_lowercase(&name[WEBKIT_PREFIX.len()..]);
return Some(PseudoElement::UnknownWebkit(part.into()));
}
}
}
}
@ -259,7 +279,7 @@ impl PseudoElement {
/// Returns `None` if the pseudo-element is not recognized.
#[inline]
pub fn tree_pseudo_element(name: &str, args: Box<[Atom]>) -> Option<Self> {
debug_assert!(name.starts_with("-moz-tree-"));
debug_assert!(starts_with_ignore_ascii_case(name, "-moz-tree-"));
let tree_part = &name[10..];
% for pseudo in TREE_PSEUDOS:
if tree_part.eq_ignore_ascii_case("${pseudo.value[11:]}") {
@ -277,6 +297,10 @@ impl ToCss for PseudoElement {
% for pseudo in PSEUDOS:
${pseudo_element_variant(pseudo)} => dest.write_str("${pseudo.value}")?,
% endfor
PseudoElement::UnknownWebkit(ref atom) => {
dest.write_str(":-webkit-")?;
serialize_atom_identifier(atom, dest)?;
}
}
if let Some(args) = self.tree_pseudo_args() {
if !args.is_empty() {

View file

@ -17,9 +17,11 @@ use selectors::parser::{SelectorParseErrorKind, Visit};
use selectors::parser::{self as selector_parser, Selector};
use selectors::visitor::SelectorVisitor;
use std::fmt;
use str::starts_with_ignore_ascii_case;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss as ToCss_};
use thin_slice::ThinBoxedSlice;
use values::serialize_atom_identifier;
pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, PSEUDO_COUNT};
pub use gecko::snapshot::SnapshotMap;
@ -35,12 +37,11 @@ bitflags! {
}
}
/// The type used for storing pseudo-class string arguments.
pub type PseudoClassStringArg = ThinBoxedSlice<u16>;
/// The type used to store the language argument to the `:lang` pseudo-class.
pub type Lang = Atom;
macro_rules! pseudo_class_name {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => {
/// Our representation of a non tree-structural pseudo-class.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
pub enum NonTSPseudoClass {
@ -48,19 +49,17 @@ macro_rules! pseudo_class_name {
#[doc = $css]
$name,
)*
$(
#[doc = $s_css]
$s_name(PseudoClassStringArg),
)*
/// The `:lang` pseudo-class.
Lang(Lang),
/// The `:dir` pseudo-class.
Dir(Box<Direction>),
Dir(Direction),
/// The non-standard `:-moz-any` pseudo-class.
///
/// TODO(emilio): We disallow combinators and pseudos here, so we
/// should use SimpleSelector instead
MozAny(ThinBoxedSlice<Selector<SelectorImpl>>),
/// The non-standard `:-moz-locale-dir` pseudo-class.
MozLocaleDir(Box<Direction>),
MozLocaleDir(Direction),
}
}
}
@ -71,25 +70,15 @@ impl ToCss for NonTSPseudoClass {
where
W: fmt::Write,
{
use cssparser::CssStringWriter;
use std::fmt::Write;
macro_rules! pseudo_class_serialize {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => {
match *self {
$(NonTSPseudoClass::$name => concat!(":", $css),)*
$(NonTSPseudoClass::$s_name(ref s) => {
dest.write_str(concat!(":", $s_css, "("))?;
{
// FIXME(emilio): Avoid the extra allocation!
let mut css = CssStringWriter::new(dest);
// Discount the null char in the end from the
// string.
css.write_str(&String::from_utf16(&s[..s.len() - 1]).unwrap())?;
}
return dest.write_str(")")
}, )*
NonTSPseudoClass::Lang(ref s) => {
dest.write_str(":lang(")?;
serialize_atom_identifier(s, dest)?;
return dest.write_char(')');
},
NonTSPseudoClass::MozLocaleDir(ref dir) => {
dest.write_str(":-moz-locale-dir(")?;
dir.to_css(&mut CssWriter::new(dest))?;
@ -109,7 +98,7 @@ impl ToCss for NonTSPseudoClass {
dest.write_str(", ")?;
selector.to_css(dest)?;
}
return dest.write_str(")")
return dest.write_char(')')
}
}
}
@ -144,8 +133,7 @@ impl NonTSPseudoClass {
/// in a particular state.
pub fn parse_non_functional(name: &str) -> Option<Self> {
macro_rules! pseudo_class_parse {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => {
match_ignore_ascii_case! { &name,
$($css => Some(NonTSPseudoClass::$name),)*
_ => None,
@ -166,12 +154,11 @@ impl NonTSPseudoClass {
};
}
macro_rules! pseudo_class_check_is_enabled_in {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => {
match *self {
$(NonTSPseudoClass::$name => check_flag!($flags),)*
$(NonTSPseudoClass::$s_name(..) => check_flag!($s_flags),)*
NonTSPseudoClass::MozLocaleDir(_) |
NonTSPseudoClass::Lang(_) |
NonTSPseudoClass::Dir(_) |
NonTSPseudoClass::MozAny(_) => false,
}
@ -221,13 +208,12 @@ impl NonTSPseudoClass {
};
}
macro_rules! pseudo_class_state {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
([$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*]) => {
match *self {
$(NonTSPseudoClass::$name => flag!($state),)*
$(NonTSPseudoClass::$s_name(..) => flag!($s_state),)*
NonTSPseudoClass::Dir(..) |
NonTSPseudoClass::MozLocaleDir(..) |
NonTSPseudoClass::Lang(..) |
NonTSPseudoClass::MozAny(..) => ElementState::empty(),
}
}
@ -398,42 +384,29 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
name: CowRcStr<'i>,
parser: &mut Parser<'i, 't>,
) -> Result<NonTSPseudoClass, ParseError<'i>> {
macro_rules! pseudo_class_string_parse {
(bare: [$(($css:expr, $name:ident, $gecko_type:tt, $state:tt, $flags:tt),)*],
string: [$(($s_css:expr, $s_name:ident, $s_gecko_type:tt, $s_state:tt, $s_flags:tt),)*]) => {
match_ignore_ascii_case! { &name,
$($s_css => {
let name = parser.expect_ident_or_string()?;
// convert to null terminated utf16 string
// since that's what Gecko deals with
let utf16: Vec<u16> = name.encode_utf16().chain(Some(0u16)).collect();
NonTSPseudoClass::$s_name(utf16.into_boxed_slice().into())
}, )*
"-moz-locale-dir" => {
NonTSPseudoClass::MozLocaleDir(
Box::new(Direction::parse(parser)?)
)
},
"dir" => {
NonTSPseudoClass::Dir(
Box::new(Direction::parse(parser)?)
)
},
"-moz-any" => {
NonTSPseudoClass::MozAny(
selector_parser::parse_compound_selector_list(
self,
parser,
)?.into()
)
}
_ => return Err(parser.new_custom_error(
SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone())
))
}
let pseudo_class = match_ignore_ascii_case! { &name,
"lang" => {
let name = parser.expect_ident_or_string()?;
NonTSPseudoClass::Lang(Atom::from(name.as_ref()))
},
"-moz-locale-dir" => {
NonTSPseudoClass::MozLocaleDir(Direction::parse(parser)?)
},
"dir" => {
NonTSPseudoClass::Dir(Direction::parse(parser)?)
},
"-moz-any" => {
NonTSPseudoClass::MozAny(
selector_parser::parse_compound_selector_list(
self,
parser,
)?.into()
)
}
}
let pseudo_class = apply_non_ts_list!(pseudo_class_string_parse);
_ => return Err(parser.new_custom_error(
SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name.clone())
))
};
if self.is_pseudo_class_enabled(&pseudo_class) {
Ok(pseudo_class)
} else {
@ -468,8 +441,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
name: CowRcStr<'i>,
parser: &mut Parser<'i, 't>,
) -> Result<PseudoElement, ParseError<'i>> {
// FIXME: -moz-tree check should probably be ascii-case-insensitive.
if name.starts_with("-moz-tree-") {
if starts_with_ignore_ascii_case(&name, "-moz-tree-") {
// Tree pseudo-elements can have zero or more arguments, separated
// by either comma or space.
let mut args = Vec::new();

View file

@ -69,7 +69,7 @@ use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
use properties::animated_properties::{AnimationValue, AnimationValueMap};
use properties::style_structs::Font;
use rule_tree::CascadeLevel as ServoCascadeLevel;
use selector_parser::{AttrValue, Direction, PseudoClassStringArg};
use selector_parser::{AttrValue, HorizontalDirection, Lang};
use selectors::{Element, OpaqueElement};
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator};
use selectors::attr::{CaseSensitivity, NamespaceConstraint};
@ -167,15 +167,14 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> {
}
#[inline]
fn style_data<'a>(&self) -> &'a CascadeData
fn style_data<'a>(&self) -> Option<&'a CascadeData>
where
Self: 'a,
{
debug_assert!(!self.0.mServoStyles.mPtr.is_null());
let author_styles = unsafe {
&*(self.0.mServoStyles.mPtr as *const structs::RawServoAuthorStyles
as *const bindings::RawServoAuthorStyles)
(self.0.mServoStyles.mPtr
as *const structs::RawServoAuthorStyles
as *const bindings::RawServoAuthorStyles).as_ref()?
};
@ -187,7 +186,7 @@ impl<'lr> TShadowRoot for GeckoShadowRoot<'lr> {
author_styles.stylesheets.dirty()
);
&author_styles.data
Some(&author_styles.data)
}
#[inline]
@ -1717,15 +1716,11 @@ impl<'le> TElement for GeckoElement<'le> {
fn match_element_lang(
&self,
override_lang: Option<Option<AttrValue>>,
value: &PseudoClassStringArg,
value: &Lang,
) -> bool {
// Gecko supports :lang() from CSS Selectors 3, which only accepts a
// single language tag, and which performs simple dash-prefix matching
// on it.
debug_assert!(
value.len() > 0 && value[value.len() - 1] == 0,
"expected value to be null terminated"
);
let override_lang_ptr = match &override_lang {
&Some(Some(ref atom)) => atom.as_ptr(),
_ => ptr::null_mut(),
@ -1735,7 +1730,7 @@ impl<'le> TElement for GeckoElement<'le> {
self.0,
override_lang_ptr,
override_lang.is_some(),
value.as_ptr(),
value.as_slice().as_ptr(),
)
}
}
@ -2238,24 +2233,22 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::MozLocaleDir(ref dir) => {
let state_bit = DocumentState::NS_DOCUMENT_STATE_RTL_LOCALE;
if context.extra_data.document_state.intersects(state_bit) {
// NOTE(emilio): We could still return false for
// Direction::Other(..), but we don't bother.
// NOTE(emilio): We could still return false for values
// other than "ltr" and "rtl", but we don't bother.
return !context.in_negation();
}
let doc_is_rtl = self.document_state().contains(state_bit);
match **dir {
Direction::Ltr => !doc_is_rtl,
Direction::Rtl => doc_is_rtl,
Direction::Other(..) => false,
match dir.as_horizontal_direction() {
Some(HorizontalDirection::Ltr) => !doc_is_rtl,
Some(HorizontalDirection::Rtl) => doc_is_rtl,
None => false,
}
},
NonTSPseudoClass::Dir(ref dir) => match **dir {
Direction::Ltr => self.state().intersects(ElementState::IN_LTR_STATE),
Direction::Rtl => self.state().intersects(ElementState::IN_RTL_STATE),
Direction::Other(..) => false,
},
NonTSPseudoClass::Dir(ref dir) => {
self.state().intersects(dir.element_state())
}
}
}

View file

@ -305,6 +305,15 @@ pub struct OwnedOrNull<GeckoType> {
}
impl<GeckoType> OwnedOrNull<GeckoType> {
/// Returns a null pointer.
#[inline]
pub fn null() -> Self {
Self {
ptr: ptr::null_mut(),
_marker: PhantomData,
}
}
/// Returns whether this pointer is null.
#[inline]
pub fn is_null(&self) -> bool {

View file

@ -188,8 +188,7 @@ where
// support we don't forget to update this code?
#[cfg(feature = "gecko")]
NonTSPseudoClass::Dir(ref dir) => {
use invalidation::element::invalidation_map::dir_selector_to_state;
let selector_flag = dir_selector_to_state(dir);
let selector_flag = dir.element_state();
if selector_flag.is_empty() {
// :dir() with some random argument; does not match.
return false;

View file

@ -10,8 +10,6 @@ use element_state::{DocumentState, ElementState};
use fallible::FallibleVec;
use hashglobe::FailedAllocationError;
use selector_map::{MaybeCaseInsensitiveHashMap, SelectorMap, SelectorMapEntry};
#[cfg(feature = "gecko")]
use selector_parser::Direction;
use selector_parser::SelectorImpl;
use selectors::attr::NamespaceConstraint;
use selectors::parser::{Combinator, Component};
@ -19,20 +17,6 @@ use selectors::parser::{Selector, SelectorIter, Visit};
use selectors::visitor::SelectorVisitor;
use smallvec::SmallVec;
#[cfg(feature = "gecko")]
/// Gets the element state relevant to the given `:dir` pseudo-class selector.
pub fn dir_selector_to_state(dir: &Direction) -> ElementState {
match *dir {
Direction::Ltr => ElementState::IN_LTR_STATE,
Direction::Rtl => ElementState::IN_RTL_STATE,
Direction::Other(_) => {
// :dir(something-random) is a valid selector, but shouldn't
// match anything.
ElementState::empty()
},
}
}
/// Mapping between (partial) CompoundSelectors (and the combinator to their
/// right) and the states and attributes they depend on.
///
@ -382,7 +366,7 @@ impl<'a> SelectorVisitor for CompoundSelectorDependencyCollector<'a> {
self.other_attributes |= pc.is_attr_based();
self.state |= match *pc {
#[cfg(feature = "gecko")]
NonTSPseudoClass::Dir(ref dir) => dir_selector_to_state(dir),
NonTSPseudoClass::Dir(ref dir) => dir.element_state(),
_ => pc.state_flag(),
};
*self.document_state |= pc.document_state_flag();

View file

@ -159,13 +159,18 @@ where
// force a restyle here. Matching doesn't depend on the actual visited
// state at all, so we can't look at matching results to decide what to
// do for this case.
if state_changes.intersects(ElementState::IN_VISITED_OR_UNVISITED_STATE) {
if state_changes.intersects(ElementState::IN_VISITED_OR_UNVISITED_STATE) &&
self.shared_context.visited_styles_enabled
{
trace!(" > visitedness change, force subtree restyle");
// If we get here with visited links disabled, we should probably
// just avoid the restyle and remove the state change here, not only
// as an optimization, but also because it kind of would kill the
// We shouldn't get here with visited links disabled, but it's hard
// to assert in cases where you record a visitedness change and
// afterwards you change some of the stuff (like the pref) that
// changes whether visited styles are enabled.
//
// So just avoid the restyle here, because it kind of would kill the
// point of disabling visited links.
debug_assert!(self.shared_context.visited_styles_enabled);
//
// We can't just return here because there may also be attribute
// changes as well that imply additional hints for siblings.
self.data.hint.insert(RestyleHint::restyle_subtree());

View file

@ -157,6 +157,7 @@ pub mod thread_state;
pub mod timer;
pub mod traversal;
pub mod traversal_flags;
pub mod use_counters;
#[macro_use]
#[allow(non_camel_case_types)]
pub mod values;

View file

@ -9,6 +9,7 @@ use cssparser::{Parser, SourceLocation, UnicodeRange};
use error_reporting::{ContextualParseError, ParseErrorReporter};
use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
use stylesheets::{CssRuleType, Namespaces, Origin, UrlExtraData};
use use_counters::UseCounters;
/// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
#[cfg(feature = "gecko")]
@ -53,6 +54,8 @@ pub struct ParserContext<'a> {
error_reporter: Option<&'a ParseErrorReporter>,
/// The currently active namespaces.
pub namespaces: Option<&'a Namespaces>,
/// The use counters we want to record while parsing style rules, if any.
pub use_counters: Option<&'a UseCounters>,
}
impl<'a> ParserContext<'a> {
@ -65,8 +68,9 @@ impl<'a> ParserContext<'a> {
parsing_mode: ParsingMode,
quirks_mode: QuirksMode,
error_reporter: Option<&'a ParseErrorReporter>,
use_counters: Option<&'a UseCounters>,
) -> Self {
ParserContext {
Self {
stylesheet_origin,
url_data,
rule_type,
@ -74,6 +78,7 @@ impl<'a> ParserContext<'a> {
quirks_mode,
error_reporter,
namespaces: None,
use_counters,
}
}
@ -85,6 +90,7 @@ impl<'a> ParserContext<'a> {
parsing_mode: ParsingMode,
quirks_mode: QuirksMode,
error_reporter: Option<&'a ParseErrorReporter>,
use_counters: Option<&'a UseCounters>,
) -> Self {
Self::new(
Origin::Author,
@ -93,17 +99,19 @@ impl<'a> ParserContext<'a> {
parsing_mode,
quirks_mode,
error_reporter,
use_counters,
)
}
/// Create a parser context based on a previous context, but with a modified rule type.
/// Create a parser context based on a previous context, but with a modified
/// rule type.
#[inline]
pub fn new_with_rule_type(
context: &'a ParserContext,
rule_type: CssRuleType,
namespaces: &'a Namespaces,
) -> ParserContext<'a> {
ParserContext {
Self {
stylesheet_origin: context.stylesheet_origin,
url_data: context.url_data,
rule_type: Some(rule_type),
@ -111,6 +119,7 @@ impl<'a> ParserContext<'a> {
quirks_mode: context.quirks_mode,
namespaces: Some(namespaces),
error_reporter: context.error_reporter,
use_counters: context.use_counters,
}
}

View file

@ -138,56 +138,9 @@ impl<'a> DoubleEndedIterator for DeclarationImportanceIterator<'a> {
}
}
/// Iterator over `PropertyDeclaration` for Importance::Normal.
///
/// TODO(emilio): This should be replaced by `impl Trait`, returning a
/// filter()ed iterator when available instead, and all the boilerplate below
/// should go.
pub struct NormalDeclarationIterator<'a>(DeclarationImportanceIterator<'a>);
impl<'a> NormalDeclarationIterator<'a> {
#[inline]
fn new(declarations: &'a [PropertyDeclaration], important: &'a SmallBitVec) -> Self {
NormalDeclarationIterator(
DeclarationImportanceIterator::new(declarations, important)
)
}
}
impl<'a> Iterator for NormalDeclarationIterator<'a> {
type Item = &'a PropertyDeclaration;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
loop {
let (decl, importance) = self.0.iter.next()?;
if !importance {
return Some(decl);
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.iter.size_hint()
}
}
impl<'a> DoubleEndedIterator for NormalDeclarationIterator<'a> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
loop {
let (decl, importance) = self.0.iter.next_back()?;
if !importance {
return Some(decl);
}
}
}
}
/// Iterator for AnimationValue to be generated from PropertyDeclarationBlock.
pub struct AnimationValueIterator<'a, 'cx, 'cx_a:'cx> {
iter: NormalDeclarationIterator<'a>,
iter: DeclarationImportanceIterator<'a>,
context: &'cx mut Context<'cx_a>,
default_values: &'a ComputedValues,
/// Custom properties in a keyframe if exists.
@ -202,7 +155,7 @@ impl<'a, 'cx, 'cx_a:'cx> AnimationValueIterator<'a, 'cx, 'cx_a> {
extra_custom_properties: Option<&'a Arc<::custom_properties::CustomPropertiesMap>>,
) -> AnimationValueIterator<'a, 'cx, 'cx_a> {
AnimationValueIterator {
iter: declarations.normal_declaration_iter(),
iter: declarations.declaration_importance_iter(),
context,
default_values,
extra_custom_properties,
@ -215,7 +168,11 @@ impl<'a, 'cx, 'cx_a:'cx> Iterator for AnimationValueIterator<'a, 'cx, 'cx_a> {
#[inline]
fn next(&mut self) -> Option<Self::Item> {
loop {
let decl = self.iter.next()?;
let (decl, importance) = self.iter.next()?;
if importance.important() {
continue;
}
let animation = AnimationValue::from_declaration(
decl,
@ -287,8 +244,12 @@ impl PropertyDeclarationBlock {
/// Iterate over `PropertyDeclaration` for Importance::Normal
#[inline]
pub fn normal_declaration_iter(&self) -> NormalDeclarationIterator {
NormalDeclarationIterator::new(&self.declarations, &self.declarations_importance)
pub fn normal_declaration_iter<'a>(
&'a self,
) -> impl DoubleEndedIterator<Item = &'a PropertyDeclaration> {
self.declaration_importance_iter()
.filter(|(_, importance)| !importance.important())
.map(|(declaration, _)| declaration)
}
/// Return an iterator of (AnimatableLonghand, AnimationValue).
@ -344,14 +305,8 @@ impl PropertyDeclarationBlock {
}
}
self.declarations.iter().enumerate().find(|&(_, decl)| decl.id() == property).map(|(i, decl)| {
let importance = if self.declarations_importance[i] {
Importance::Important
} else {
Importance::Normal
};
(decl, importance)
})
self.declaration_importance_iter()
.find(|(declaration, _)| declaration.id() == property)
}
fn shorthand_to_css(
@ -1248,6 +1203,7 @@ pub fn parse_style_attribute(
ParsingMode::DEFAULT,
quirks_mode,
error_reporter,
None,
);
let mut input = ParserInput::new(input);
@ -1275,6 +1231,7 @@ pub fn parse_one_declaration_into(
parsing_mode,
quirks_mode,
error_reporter,
None,
);
let mut input = ParserInput::new(input);

View file

@ -3053,7 +3053,7 @@ fn static_assert() {
scroll-snap-points-x scroll-snap-points-y
scroll-snap-type-x scroll-snap-type-y scroll-snap-coordinate
perspective-origin -moz-binding will-change
overscroll-behavior-x overscroll-behavior-y
offset-path overscroll-behavior-x overscroll-behavior-y
overflow-clip-box-inline overflow-clip-box-block
perspective-origin -moz-binding will-change
shape-outside contain touch-action translate
@ -3681,6 +3681,40 @@ fn static_assert() {
${impl_simple_copy("contain", "mContain")}
${impl_simple_type_with_conversion("touch_action")}
pub fn set_offset_path(&mut self, v: longhands::offset_path::computed_value::T) {
use gecko_bindings::bindings::{Gecko_NewStyleMotion, Gecko_SetStyleMotion};
use gecko_bindings::structs::StyleShapeSourceType;
use values::generics::basic_shape::FillRule;
use values::specified::OffsetPath;
let motion = unsafe { Gecko_NewStyleMotion().as_mut().unwrap() };
match v {
OffsetPath::None => motion.mOffsetPath.mType = StyleShapeSourceType::None,
OffsetPath::Path(p) => {
set_style_svg_path(&mut motion.mOffsetPath, &p, FillRule::Nonzero)
},
}
unsafe { Gecko_SetStyleMotion(&mut self.gecko.mMotion, motion) };
}
pub fn clone_offset_path(&self) -> longhands::offset_path::computed_value::T {
use values::specified::OffsetPath;
match unsafe { self.gecko.mMotion.mPtr.as_ref() } {
None => OffsetPath::none(),
Some(v) => (&v.mOffsetPath).into()
}
}
pub fn copy_offset_path_from(&mut self, other: &Self) {
use gecko_bindings::bindings::Gecko_CopyStyleMotions;
unsafe { Gecko_CopyStyleMotions(&mut self.gecko.mMotion, other.gecko.mMotion.mPtr) };
}
pub fn reset_offset_path(&mut self, other: &Self) {
self.copy_offset_path_from(other);
}
</%self:impl_trait>
<%def name="simple_image_array_property(name, shorthand, field_name)">
@ -4937,14 +4971,43 @@ fn static_assert() {
}
</%self:impl_trait>
// Set SVGPathData to StyleShapeSource.
fn set_style_svg_path(
shape_source: &mut structs::mozilla::StyleShapeSource,
servo_path: &values::specified::svg_path::SVGPathData,
fill: values::generics::basic_shape::FillRule,
) {
use gecko_bindings::bindings::Gecko_NewStyleSVGPath;
use gecko_bindings::structs::StyleShapeSourceType;
// Setup type.
shape_source.mType = StyleShapeSourceType::Path;
// Setup path.
let gecko_path = unsafe {
Gecko_NewStyleSVGPath(shape_source);
&mut shape_source.__bindgen_anon_1.mSVGPath.as_mut().mPtr.as_mut().unwrap()
};
unsafe { gecko_path.mPath.set_len(servo_path.commands().len() as u32) };
debug_assert_eq!(gecko_path.mPath.len(), servo_path.commands().len());
for (servo, gecko) in servo_path.commands().iter().zip(gecko_path.mPath.iter_mut()) {
// unsafe: cbindgen ensures the representation is the same.
*gecko = unsafe { transmute(*servo) };
}
// Setup fill-rule.
// unsafe: cbindgen ensures the representation is the same.
gecko_path.mFillRule = unsafe { transmute(fill) };
}
<%def name="impl_shape_source(ident, gecko_ffi_name)">
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
use gecko_bindings::bindings::{Gecko_NewBasicShape, Gecko_DestroyShapeSource};
use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleShapeSourceType};
use gecko_bindings::structs::{StyleFillRule, StyleGeometryBox, StyleShapeSource};
use gecko_bindings::structs::{StyleGeometryBox, StyleShapeSource};
use gecko::conversions::basic_shape::set_corners_from_radius;
use gecko::values::GeckoStyleCoordConvertible;
use values::generics::basic_shape::{BasicShape, FillRule, ShapeSource};
use values::generics::basic_shape::{BasicShape, ShapeSource};
let ref mut ${ident} = self.gecko.${gecko_ffi_name};
@ -4976,6 +5039,7 @@ fn static_assert() {
${ident}.mReferenceBox = reference.into();
${ident}.mType = StyleShapeSourceType::Box;
}
ShapeSource::Path(p) => set_style_svg_path(${ident}, &p.path, p.fill),
ShapeSource::Shape(servo_shape, maybe_box) => {
fn init_shape(${ident}: &mut StyleShapeSource, basic_shape_type: StyleBasicShapeType)
-> &mut StyleBasicShape {
@ -5038,11 +5102,8 @@ fn static_assert() {
coord.0.to_gecko_style_coord(&mut shape.mCoordinates[2 * i]);
coord.1.to_gecko_style_coord(&mut shape.mCoordinates[2 * i + 1]);
}
shape.mFillRule = if poly.fill == FillRule::Evenodd {
StyleFillRule::Evenodd
} else {
StyleFillRule::Nonzero
};
// unsafe: cbindgen ensures the representation is the same.
shape.mFillRule = unsafe { transmute(poly.fill) };
}
}

View file

@ -18,14 +18,17 @@ ${helpers.predefined_type(
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
)}
${helpers.predefined_type("background-image", "ImageLayer",
${helpers.predefined_type(
"background-image",
"ImageLayer",
initial_value="Either::First(None_)",
initial_specified_value="Either::First(None_)",
spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
vector="True",
animation_value_type="discrete",
ignored_when_colors_disabled="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",
)}
% for (axis, direction, initial) in [("x", "Horizontal", "left"), ("y", "Vertical", "top")]:
${helpers.predefined_type(
@ -52,13 +55,15 @@ ${helpers.predefined_type(
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
)}
${helpers.single_keyword("background-attachment",
"scroll fixed" + (" local" if product == "gecko" else ""),
vector=True,
gecko_enum_prefix="StyleImageLayerAttachment",
spec="https://drafts.csswg.org/css-backgrounds/#the-background-attachment",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")}
${helpers.single_keyword(
"background-attachment",
"scroll fixed" + (" local" if product == "gecko" else ""),
vector=True,
gecko_enum_prefix="StyleImageLayerAttachment",
spec="https://drafts.csswg.org/css-backgrounds/#the-background-attachment",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
)}
${helpers.single_keyword(
"background-clip",
@ -96,12 +101,14 @@ ${helpers.predefined_type(
extra_prefixes="webkit")}
// https://drafts.fxtf.org/compositing/#background-blend-mode
${helpers.single_keyword("background-blend-mode",
"""normal multiply screen overlay darken lighten color-dodge
color-burn hard-light soft-light difference exclusion hue
saturation color luminosity""",
gecko_constant_prefix="NS_STYLE_BLEND",
gecko_pref="layout.css.background-blend-mode.enabled",
vector=True, products="gecko", animation_value_type="discrete",
spec="https://drafts.fxtf.org/compositing/#background-blend-mode",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")}
${helpers.single_keyword(
"background-blend-mode",
"""normal multiply screen overlay darken lighten color-dodge
color-burn hard-light soft-light difference exclusion hue
saturation color luminosity""",
gecko_constant_prefix="NS_STYLE_BLEND",
gecko_pref="layout.css.background-blend-mode.enabled",
vector=True, products="gecko", animation_value_type="discrete",
spec="https://drafts.fxtf.org/compositing/#background-blend-mode",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
)}

View file

@ -61,51 +61,70 @@
)}
% endfor
${helpers.gecko_keyword_conversion(Keyword('border-style',
"none solid double dotted dashed hidden groove ridge inset outset"),
type="::values::specified::BorderStyle")}
${helpers.gecko_keyword_conversion(
Keyword('border-style',
"none solid double dotted dashed hidden groove ridge inset outset"),
type="::values::specified::BorderStyle",
)}
// FIXME(#4126): when gfx supports painting it, make this Size2D<LengthOrPercentage>
% for corner in ["top-left", "top-right", "bottom-right", "bottom-left"]:
${helpers.predefined_type("border-" + corner + "-radius", "BorderCornerRadius",
"computed::BorderCornerRadius::zero()",
"parse", extra_prefixes="webkit",
spec="https://drafts.csswg.org/css-backgrounds/#border-%s-radius" % corner,
boxed=True,
flags="APPLIES_TO_FIRST_LETTER",
animation_value_type="BorderCornerRadius")}
${helpers.predefined_type(
"border-" + corner + "-radius",
"BorderCornerRadius",
"computed::BorderCornerRadius::zero()",
"parse",
extra_prefixes="webkit",
spec="https://drafts.csswg.org/css-backgrounds/#border-%s-radius" % corner,
boxed=True,
flags="APPLIES_TO_FIRST_LETTER",
animation_value_type="BorderCornerRadius",
)}
% endfor
${helpers.single_keyword("box-decoration-break", "slice clone",
gecko_enum_prefix="StyleBoxDecorationBreak",
gecko_pref="layout.css.box-decoration-break.enabled",
spec="https://drafts.csswg.org/css-break/#propdef-box-decoration-break",
products="gecko", animation_value_type="discrete")}
${helpers.single_keyword(
"box-decoration-break",
"slice clone",
gecko_enum_prefix="StyleBoxDecorationBreak",
gecko_pref="layout.css.box-decoration-break.enabled",
spec="https://drafts.csswg.org/css-break/#propdef-box-decoration-break",
products="gecko",
animation_value_type="discrete",
)}
${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
gecko_ffi_name="mFloatEdge",
gecko_enum_prefix="StyleFloatEdge",
products="gecko",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)",
animation_value_type="discrete")}
${helpers.single_keyword(
"-moz-float-edge",
"content-box margin-box",
gecko_ffi_name="mFloatEdge",
gecko_enum_prefix="StyleFloatEdge",
products="gecko",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)",
animation_value_type="discrete",
)}
${helpers.predefined_type("border-image-source", "ImageLayer",
${helpers.predefined_type(
"border-image-source",
"ImageLayer",
initial_value="Either::First(None_)",
initial_specified_value="Either::First(None_)",
spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
vector=False,
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER",
boxed=True)}
boxed=True,
)}
${helpers.predefined_type("border-image-outset", "LengthOrNumberRect",
${helpers.predefined_type(
"border-image-outset",
"LengthOrNumberRect",
parse_method="parse_non_negative",
initial_value="computed::LengthOrNumberRect::all(computed::LengthOrNumber::zero())",
initial_specified_value="specified::LengthOrNumberRect::all(specified::LengthOrNumber::zero())",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER",
boxed=True)}
boxed=True,
)}
${helpers.predefined_type(
"border-image-repeat",
@ -117,21 +136,27 @@ ${helpers.predefined_type(
flags="APPLIES_TO_FIRST_LETTER",
)}
${helpers.predefined_type("border-image-width", "BorderImageWidth",
${helpers.predefined_type(
"border-image-width",
"BorderImageWidth",
initial_value="computed::BorderImageWidth::all(computed::BorderImageSideWidth::one())",
initial_specified_value="specified::BorderImageWidth::all(specified::BorderImageSideWidth::one())",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-width",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER",
boxed=True)}
boxed=True,
)}
${helpers.predefined_type("border-image-slice", "BorderImageSlice",
${helpers.predefined_type(
"border-image-slice",
"BorderImageSlice",
initial_value="computed::NumberOrPercentage::Percentage(computed::Percentage(1.)).into()",
initial_specified_value="specified::NumberOrPercentage::Percentage(specified::Percentage::new(1.)).into()",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER",
boxed=True)}
boxed=True,
)}
#[cfg(feature = "gecko")]
impl ::values::computed::BorderImageWidth {
@ -155,8 +180,9 @@ impl ::values::computed::BorderImageWidth {
% endfor
}
pub fn from_gecko_rect(sides: &::gecko_bindings::structs::nsStyleSides)
-> Option<::values::computed::BorderImageWidth> {
pub fn from_gecko_rect(
sides: &::gecko_bindings::structs::nsStyleSides,
) -> Option<::values::computed::BorderImageWidth> {
use gecko_bindings::structs::nsStyleUnit::{eStyleUnit_Factor, eStyleUnit_Auto};
use gecko_bindings::sugar::ns_style_coord::CoordData;
use gecko::values::GeckoStyleCoordConvertible;

View file

@ -23,36 +23,25 @@ ${helpers.predefined_type(
needs_context=product == "gecko"
)}
// FIXME(emilio): Listing all the display values here is very unfortunate, we should teach C++ to use the
// Rust enum directly, or generate the conversions to `StyleDisplay`.
${helpers.gecko_keyword_conversion(
Keyword('display', """
inline block inline-block
table inline-table table-row-group table-header-group table-footer-group
table-row table-column-group table-column table-cell table-caption
list-item none flex inline-flex grid inline-grid ruby ruby-base ruby-base-container
ruby-text ruby-text-container contents flow-root -webkit-box
-webkit-inline-box -moz-box -moz-inline-box -moz-grid -moz-inline-grid
-moz-grid-group -moz-grid-line -moz-stack -moz-inline-stack -moz-deck
-moz-popup -moz-groupbox
""",
gecko_enum_prefix='StyleDisplay',
gecko_strip_moz_prefix=False),
type="::values::specified::Display"
${helpers.single_keyword(
"-moz-top-layer",
"none top",
gecko_constant_prefix="NS_STYLE_TOP_LAYER",
gecko_ffi_name="mTopLayer",
products="gecko",
animation_value_type="none",
enabled_in="ua",
spec="Internal (not web-exposed)",
)}
${helpers.single_keyword("-moz-top-layer", "none top",
gecko_constant_prefix="NS_STYLE_TOP_LAYER",
gecko_ffi_name="mTopLayer",
products="gecko", animation_value_type="none",
enabled_in="ua",
spec="Internal (not web-exposed)")}
${helpers.single_keyword("position", "static absolute relative fixed sticky",
animation_value_type="discrete",
flags="CREATES_STACKING_CONTEXT ABSPOS_CB",
spec="https://drafts.csswg.org/css-position/#position-property",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.single_keyword(
"position",
"static absolute relative fixed sticky",
animation_value_type="discrete",
flags="CREATES_STACKING_CONTEXT ABSPOS_CB",
spec="https://drafts.csswg.org/css-position/#position-property",
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.predefined_type(
"float",
@ -64,7 +53,7 @@ ${helpers.predefined_type(
needs_context=False,
flags="APPLIES_TO_FIRST_LETTER",
servo_restyle_damage="rebuild_and_reflow",
gecko_ffi_name="mFloat"
gecko_ffi_name="mFloat",
)}
${helpers.predefined_type(
@ -75,7 +64,7 @@ ${helpers.predefined_type(
needs_context=False,
gecko_ffi_name="mBreakType",
spec="https://drafts.csswg.org/css-box/#propdef-clear",
servo_restyle_damage="rebuild_and_reflow"
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.predefined_type(
@ -85,7 +74,7 @@ ${helpers.predefined_type(
animation_value_type="ComputedValue",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align",
servo_restyle_damage = "reflow"
servo_restyle_damage = "reflow",
)}
// CSS 2.1, Section 11 - Visual effects
@ -118,14 +107,17 @@ ${helpers.single_keyword("-servo-overflow-clip-box", "padding-box content-box",
// FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`.
//
// We allow it to apply to placeholders for UA sheets, which set it !important.
${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
animation_value_type="discrete",
extra_gecko_values="-moz-hidden-unscrollable",
custom_consts=overflow_custom_consts,
gecko_constant_prefix="NS_STYLE_OVERFLOW",
flags="APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-overflow/#propdef-overflow-x",
servo_restyle_damage = "reflow")}
${helpers.single_keyword(
"overflow-x",
"visible hidden scroll auto",
animation_value_type="discrete",
extra_gecko_values="-moz-hidden-unscrollable",
custom_consts=overflow_custom_consts,
gecko_constant_prefix="NS_STYLE_OVERFLOW",
flags="APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-overflow/#propdef-overflow-x",
servo_restyle_damage = "reflow",
)}
// FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`.
//
@ -139,26 +131,30 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
<% transition_extra_prefixes = "moz:layout.css.prefixes.transitions webkit" %>
${helpers.predefined_type("transition-duration",
"Time",
"computed::Time::zero()",
initial_specified_value="specified::Time::zero()",
parse_method="parse_non_negative",
vector=True,
need_index=True,
animation_value_type="none",
extra_prefixes=transition_extra_prefixes,
spec="https://drafts.csswg.org/css-transitions/#propdef-transition-duration")}
${helpers.predefined_type(
"transition-duration",
"Time",
"computed::Time::zero()",
initial_specified_value="specified::Time::zero()",
parse_method="parse_non_negative",
vector=True,
need_index=True,
animation_value_type="none",
extra_prefixes=transition_extra_prefixes,
spec="https://drafts.csswg.org/css-transitions/#propdef-transition-duration",
)}
${helpers.predefined_type("transition-timing-function",
"TimingFunction",
"computed::TimingFunction::ease()",
initial_specified_value="specified::TimingFunction::ease()",
vector=True,
need_index=True,
animation_value_type="none",
extra_prefixes=transition_extra_prefixes,
spec="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function")}
${helpers.predefined_type(
"transition-timing-function",
"TimingFunction",
"computed::TimingFunction::ease()",
initial_specified_value="specified::TimingFunction::ease()",
vector=True,
need_index=True,
animation_value_type="none",
extra_prefixes=transition_extra_prefixes,
spec="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function",
)}
${helpers.predefined_type(
"transition-property",
@ -173,16 +169,17 @@ ${helpers.predefined_type(
spec="https://drafts.csswg.org/css-transitions/#propdef-transition-property",
)}
${helpers.predefined_type("transition-delay",
"Time",
"computed::Time::zero()",
initial_specified_value="specified::Time::zero()",
vector=True,
need_index=True,
animation_value_type="none",
extra_prefixes=transition_extra_prefixes,
spec="https://drafts.csswg.org/css-transitions/#propdef-transition-delay")}
${helpers.predefined_type(
"transition-delay",
"Time",
"computed::Time::zero()",
initial_specified_value="specified::Time::zero()",
vector=True,
need_index=True,
animation_value_type="none",
extra_prefixes=transition_extra_prefixes,
spec="https://drafts.csswg.org/css-transitions/#propdef-transition-delay",
)}
<% animation_extra_prefixes = "moz:layout.css.prefixes.animations webkit" %>
@ -199,29 +196,33 @@ ${helpers.predefined_type(
spec="https://drafts.csswg.org/css-animations/#propdef-animation-name",
)}
${helpers.predefined_type("animation-duration",
"Time",
"computed::Time::zero()",
initial_specified_value="specified::Time::zero()",
parse_method="parse_non_negative",
vector=True,
need_index=True,
animation_value_type="none",
extra_prefixes=animation_extra_prefixes,
spec="https://drafts.csswg.org/css-transitions/#propdef-transition-duration")}
${helpers.predefined_type(
"animation-duration",
"Time",
"computed::Time::zero()",
initial_specified_value="specified::Time::zero()",
parse_method="parse_non_negative",
vector=True,
need_index=True,
animation_value_type="none",
extra_prefixes=animation_extra_prefixes,
spec="https://drafts.csswg.org/css-transitions/#propdef-transition-duration",
)}
// animation-timing-function is the exception to the rule for allowed_in_keyframe_block:
// https://drafts.csswg.org/css-animations/#keyframes
${helpers.predefined_type("animation-timing-function",
"TimingFunction",
"computed::TimingFunction::ease()",
initial_specified_value="specified::TimingFunction::ease()",
vector=True,
need_index=True,
animation_value_type="none",
extra_prefixes=animation_extra_prefixes,
allowed_in_keyframe_block=True,
spec="https://drafts.csswg.org/css-transitions/#propdef-animation-timing-function")}
${helpers.predefined_type(
"animation-timing-function",
"TimingFunction",
"computed::TimingFunction::ease()",
initial_specified_value="specified::TimingFunction::ease()",
vector=True,
need_index=True,
animation_value_type="none",
extra_prefixes=animation_extra_prefixes,
allowed_in_keyframe_block=True,
spec="https://drafts.csswg.org/css-transitions/#propdef-animation-timing-function",
)}
${helpers.predefined_type(
"animation-iteration-count",
@ -237,46 +238,54 @@ ${helpers.predefined_type(
)}
<% animation_direction_custom_consts = { "alternate-reverse": "Alternate_reverse" } %>
${helpers.single_keyword("animation-direction",
"normal reverse alternate alternate-reverse",
need_index=True,
animation_value_type="none",
vector=True,
gecko_enum_prefix="PlaybackDirection",
custom_consts=animation_direction_custom_consts,
extra_prefixes=animation_extra_prefixes,
spec="https://drafts.csswg.org/css-animations/#propdef-animation-direction",
allowed_in_keyframe_block=False)}
${helpers.single_keyword(
"animation-direction",
"normal reverse alternate alternate-reverse",
need_index=True,
animation_value_type="none",
vector=True,
gecko_enum_prefix="PlaybackDirection",
custom_consts=animation_direction_custom_consts,
extra_prefixes=animation_extra_prefixes,
spec="https://drafts.csswg.org/css-animations/#propdef-animation-direction",
allowed_in_keyframe_block=False,
)}
${helpers.single_keyword("animation-play-state",
"running paused",
need_index=True,
animation_value_type="none",
vector=True,
extra_prefixes=animation_extra_prefixes,
spec="https://drafts.csswg.org/css-animations/#propdef-animation-play-state",
allowed_in_keyframe_block=False)}
${helpers.single_keyword(
"animation-play-state",
"running paused",
need_index=True,
animation_value_type="none",
vector=True,
extra_prefixes=animation_extra_prefixes,
spec="https://drafts.csswg.org/css-animations/#propdef-animation-play-state",
allowed_in_keyframe_block=False,
)}
${helpers.single_keyword("animation-fill-mode",
"none forwards backwards both",
need_index=True,
animation_value_type="none",
vector=True,
gecko_enum_prefix="FillMode",
extra_prefixes=animation_extra_prefixes,
spec="https://drafts.csswg.org/css-animations/#propdef-animation-fill-mode",
allowed_in_keyframe_block=False)}
${helpers.single_keyword(
"animation-fill-mode",
"none forwards backwards both",
need_index=True,
animation_value_type="none",
vector=True,
gecko_enum_prefix="FillMode",
extra_prefixes=animation_extra_prefixes,
spec="https://drafts.csswg.org/css-animations/#propdef-animation-fill-mode",
allowed_in_keyframe_block=False,
)}
${helpers.predefined_type("animation-delay",
"Time",
"computed::Time::zero()",
initial_specified_value="specified::Time::zero()",
vector=True,
need_index=True,
animation_value_type="none",
extra_prefixes=animation_extra_prefixes,
spec="https://drafts.csswg.org/css-animations/#propdef-animation-delay",
allowed_in_keyframe_block=False)}
${helpers.predefined_type(
"animation-delay",
"Time",
"computed::Time::zero()",
initial_specified_value="specified::Time::zero()",
vector=True,
need_index=True,
animation_value_type="none",
extra_prefixes=animation_extra_prefixes,
spec="https://drafts.csswg.org/css-animations/#propdef-animation-delay",
allowed_in_keyframe_block=False,
)}
% for axis in ["x", "y"]:
${helpers.predefined_type(
@ -290,14 +299,16 @@ ${helpers.predefined_type("animation-delay",
)}
% endfor
${helpers.predefined_type("scroll-snap-destination",
"Position",
"computed::Position::zero()",
products="gecko",
gecko_pref="layout.css.scroll-snap.enabled",
boxed=True,
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)",
animation_value_type="discrete")}
${helpers.predefined_type(
"scroll-snap-destination",
"Position",
"computed::Position::zero()",
products="gecko",
gecko_pref="layout.css.scroll-snap.enabled",
boxed=True,
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)",
animation_value_type="discrete",
)}
${helpers.predefined_type(
"scroll-snap-coordinate",
@ -308,7 +319,7 @@ ${helpers.predefined_type(
gecko_pref="layout.css.scroll-snap.enabled",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)",
animation_value_type="discrete",
allow_empty="NotInitial"
allow_empty="NotInitial",
)}
<% transform_extra_prefixes = "moz:layout.css.prefixes.transforms webkit" %>
@ -323,26 +334,32 @@ ${helpers.predefined_type(
flags="CREATES_STACKING_CONTEXT FIXPOS_CB \
GETCS_NEEDS_LAYOUT_FLUSH CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.csswg.org/css-transforms/#propdef-transform",
servo_restyle_damage="reflow_out_of_flow"
servo_restyle_damage="reflow_out_of_flow",
)}
${helpers.predefined_type("rotate", "Rotate",
"generics::transform::Rotate::None",
animation_value_type="ComputedValue",
boxed=True,
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
gecko_pref="layout.css.individual-transform.enabled",
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
servo_restyle_damage = "reflow_out_of_flow")}
${helpers.predefined_type(
"rotate",
"Rotate",
"generics::transform::Rotate::None",
animation_value_type="ComputedValue",
boxed=True,
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
gecko_pref="layout.css.individual-transform.enabled",
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
servo_restyle_damage = "reflow_out_of_flow",
)}
${helpers.predefined_type("scale", "Scale",
"generics::transform::Scale::None",
animation_value_type="ComputedValue",
boxed=True,
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
gecko_pref="layout.css.individual-transform.enabled",
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
servo_restyle_damage = "reflow_out_of_flow")}
${helpers.predefined_type(
"scale",
"Scale",
"generics::transform::Scale::None",
animation_value_type="ComputedValue",
boxed=True,
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
gecko_pref="layout.css.individual-transform.enabled",
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
servo_restyle_damage = "reflow_out_of_flow",
)}
${helpers.predefined_type(
"translate",
@ -353,17 +370,31 @@ ${helpers.predefined_type(
flags="CREATES_STACKING_CONTEXT FIXPOS_CB GETCS_NEEDS_LAYOUT_FLUSH",
gecko_pref="layout.css.individual-transform.enabled",
spec="https://drafts.csswg.org/css-transforms-2/#individual-transforms",
servo_restyle_damage="reflow_out_of_flow"
servo_restyle_damage="reflow_out_of_flow",
)}
// Motion Path Module Level 1
${helpers.predefined_type(
"offset-path",
"OffsetPath",
"computed::OffsetPath::none()",
products="gecko",
animation_value_type="none",
gecko_pref="layout.css.motion-path.enabled",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
spec="https://drafts.fxtf.org/motion-1/#offset-path-property",
)}
// CSSOM View Module
// https://www.w3.org/TR/cssom-view-1/
${helpers.single_keyword("scroll-behavior",
"auto smooth",
gecko_pref="layout.css.scroll-behavior.property-enabled",
products="gecko",
spec="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior",
animation_value_type="discrete")}
${helpers.single_keyword(
"scroll-behavior",
"auto smooth",
gecko_pref="layout.css.scroll-behavior.property-enabled",
products="gecko",
spec="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior",
animation_value_type="discrete",
)}
% for axis in ["x", "y"]:
${helpers.predefined_type(
@ -374,7 +405,7 @@ ${helpers.single_keyword("scroll-behavior",
needs_context=False,
gecko_pref="layout.css.scroll-snap.enabled",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-type-x)",
animation_value_type="discrete"
animation_value_type="discrete",
)}
% endfor
@ -387,38 +418,48 @@ ${helpers.single_keyword("scroll-behavior",
needs_context=False,
gecko_pref="layout.css.overscroll-behavior.enabled",
spec="https://wicg.github.io/overscroll-behavior/#overscroll-behavior-properties",
animation_value_type="discrete"
animation_value_type="discrete",
)}
% endfor
// Compositing and Blending Level 1
// http://www.w3.org/TR/compositing-1/
${helpers.single_keyword("isolation",
"auto isolate",
products="gecko",
gecko_pref="layout.css.isolation.enabled",
spec="https://drafts.fxtf.org/compositing/#isolation",
flags="CREATES_STACKING_CONTEXT",
animation_value_type="discrete")}
${helpers.single_keyword(
"isolation",
"auto isolate",
products="gecko",
gecko_pref="layout.css.isolation.enabled",
spec="https://drafts.fxtf.org/compositing/#isolation",
flags="CREATES_STACKING_CONTEXT",
animation_value_type="discrete",
)}
// TODO add support for logical values recto and verso
${helpers.single_keyword("page-break-after",
"auto always avoid left right",
products="gecko",
spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-after",
animation_value_type="discrete")}
${helpers.single_keyword("page-break-before",
"auto always avoid left right",
products="gecko",
spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-before",
animation_value_type="discrete")}
${helpers.single_keyword("page-break-inside",
"auto avoid",
products="gecko",
gecko_ffi_name="mBreakInside",
gecko_constant_prefix="NS_STYLE_PAGE_BREAK",
spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-inside",
animation_value_type="discrete")}
${helpers.single_keyword(
"page-break-after",
"auto always avoid left right",
products="gecko",
spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-after",
animation_value_type="discrete",
)}
${helpers.single_keyword(
"page-break-before",
"auto always avoid left right",
products="gecko",
spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-before",
animation_value_type="discrete",
)}
${helpers.single_keyword(
"page-break-inside",
"auto avoid",
products="gecko",
gecko_ffi_name="mBreakInside",
gecko_constant_prefix="NS_STYLE_PAGE_BREAK",
spec="https://drafts.csswg.org/css2/page.html#propdef-page-break-inside",
animation_value_type="discrete",
)}
// CSS Basic User Interface Module Level 3
// http://dev.w3.org/csswg/css-ui
@ -462,20 +503,24 @@ ${helpers.predefined_type(
servo_restyle_damage="reflow_out_of_flow"
)}
${helpers.single_keyword("backface-visibility",
"visible hidden",
spec="https://drafts.csswg.org/css-transforms/#backface-visibility-property",
extra_prefixes=transform_extra_prefixes,
animation_value_type="discrete")}
${helpers.single_keyword(
"backface-visibility",
"visible hidden",
spec="https://drafts.csswg.org/css-transforms/#backface-visibility-property",
extra_prefixes=transform_extra_prefixes,
animation_value_type="discrete",
)}
${helpers.single_keyword("transform-box",
"border-box fill-box view-box",
gecko_enum_prefix="StyleGeometryBox",
products="gecko",
gecko_pref="svg.transform-box.enabled",
spec="https://drafts.csswg.org/css-transforms/#transform-box",
gecko_inexhaustive="True",
animation_value_type="discrete")}
${helpers.single_keyword(
"transform-box",
"border-box fill-box view-box",
gecko_enum_prefix="StyleGeometryBox",
products="gecko",
gecko_pref="svg.transform-box.enabled",
spec="https://drafts.csswg.org/css-transforms/#transform-box",
gecko_inexhaustive="True",
animation_value_type="discrete",
)}
${helpers.predefined_type(
"transform-style",
@ -499,17 +544,19 @@ ${helpers.predefined_type(
boxed=True,
flags="GETCS_NEEDS_LAYOUT_FLUSH",
spec="https://drafts.csswg.org/css-transforms/#transform-origin-property",
servo_restyle_damage="reflow_out_of_flow"
servo_restyle_damage="reflow_out_of_flow",
)}
${helpers.predefined_type("contain",
"Contain",
"specified::Contain::empty()",
animation_value_type="discrete",
products="gecko",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
gecko_pref="layout.css.contain.enabled",
spec="https://drafts.csswg.org/css-contain/#contain-property")}
${helpers.predefined_type(
"contain",
"Contain",
"specified::Contain::empty()",
animation_value_type="none",
products="gecko",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
gecko_pref="layout.css.contain.enabled",
spec="https://drafts.csswg.org/css-contain/#contain-property",
)}
// Non-standard
${helpers.predefined_type(
@ -522,27 +569,33 @@ ${helpers.predefined_type(
animation_value_type="discrete",
)}
${helpers.predefined_type("-moz-binding", "url::UrlOrNone", "computed::url::UrlOrNone::none()",
products="gecko",
animation_value_type="none",
gecko_ffi_name="mBinding",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-binding)")}
${helpers.predefined_type(
"-moz-binding",
"url::UrlOrNone",
"computed::url::UrlOrNone::none()",
products="gecko",
animation_value_type="none",
gecko_ffi_name="mBinding",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-binding)",
)}
${helpers.single_keyword("-moz-orient",
"inline block horizontal vertical",
products="gecko",
gecko_ffi_name="mOrient",
gecko_enum_prefix="StyleOrient",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-orient)",
animation_value_type="discrete")}
${helpers.single_keyword(
"-moz-orient",
"inline block horizontal vertical",
products="gecko",
gecko_ffi_name="mOrient",
gecko_enum_prefix="StyleOrient",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-orient)",
animation_value_type="discrete",
)}
${helpers.predefined_type(
"will-change",
"WillChange",
"computed::WillChange::auto()",
products="gecko",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-will-change/#will-change"
animation_value_type="none",
spec="https://drafts.csswg.org/css-will-change/#will-change",
)}
${helpers.predefined_type(

View file

@ -15,7 +15,7 @@ ${helpers.predefined_type(
animation_value_type="AnimatedRGBA",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
ignored_when_colors_disabled="True",
spec="https://drafts.csswg.org/css-color/#color"
spec="https://drafts.csswg.org/css-color/#color",
)}
// FIXME(#15973): Add servo support for system colors
@ -96,8 +96,10 @@ pub mod system_colors {
#[inline]
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
unsafe {
Gecko_GetLookAndFeelSystemColor(*self as i32,
cx.device().pres_context())
Gecko_GetLookAndFeelSystemColor(
*self as i32,
cx.device().pres_context(),
)
}
}

View file

@ -6,16 +6,17 @@
<% data.new_style_struct("Column", inherited=False) %>
${helpers.predefined_type("column-width",
"length::NonNegativeLengthOrAuto",
"Either::Second(Auto)",
initial_specified_value="Either::Second(Auto)",
extra_prefixes="moz",
animation_value_type="NonNegativeLengthOrAuto",
servo_pref="layout.columns.enabled",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-width",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.predefined_type(
"column-width",
"length::NonNegativeLengthOrAuto",
"Either::Second(Auto)",
initial_specified_value="Either::Second(Auto)",
extra_prefixes="moz",
animation_value_type="NonNegativeLengthOrAuto",
servo_pref="layout.columns.enabled",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-width",
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.predefined_type(
"column-count",
@ -29,22 +30,27 @@ ${helpers.predefined_type(
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.single_keyword(
"column-fill",
"balance auto",
extra_prefixes="moz",
products="gecko",
animation_value_type="discrete",
gecko_enum_prefix="StyleColumnFill",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-fill",
)}
${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz",
products="gecko", animation_value_type="discrete",
gecko_enum_prefix="StyleColumnFill",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-fill")}
${helpers.predefined_type("column-rule-width",
"BorderSideWidth",
"::values::computed::NonNegativeLength::new(3.)",
initial_specified_value="specified::BorderSideWidth::Medium",
computed_type="::values::computed::NonNegativeLength",
products="gecko",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-width",
animation_value_type="NonNegativeLength",
extra_prefixes="moz")}
${helpers.predefined_type(
"column-rule-width",
"BorderSideWidth",
"::values::computed::NonNegativeLength::new(3.)",
initial_specified_value="specified::BorderSideWidth::Medium",
computed_type="::values::computed::NonNegativeLength",
products="gecko",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-width",
animation_value_type="NonNegativeLength",
extra_prefixes="moz",
)}
// https://drafts.csswg.org/css-multicol-1/#crc
${helpers.predefined_type(
@ -59,16 +65,23 @@ ${helpers.predefined_type(
spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-color",
)}
${helpers.single_keyword("column-span", "none all",
products="gecko", animation_value_type="discrete",
gecko_enum_prefix="StyleColumnSpan",
gecko_pref="layout.css.column-span.enabled",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-span",
extra_prefixes="moz:layout.css.column-span.enabled")}
${helpers.single_keyword(
"column-span",
"none all",
products="gecko",
animation_value_type="discrete",
gecko_enum_prefix="StyleColumnSpan",
gecko_pref="layout.css.column-span.enabled",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-span",
extra_prefixes="moz:layout.css.column-span.enabled",
)}
${helpers.single_keyword("column-rule-style",
"none hidden dotted dashed solid double groove ridge inset outset",
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")}
${helpers.single_keyword(
"column-rule-style",
"none hidden dotted dashed solid double groove ridge inset outset",
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

@ -6,13 +6,15 @@
<% data.new_style_struct("Counters", inherited=False, gecko_name="Content") %>
${helpers.predefined_type("content",
"Content",
"computed::Content::normal()",
initial_specified_value="specified::Content::normal()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-content/#propdef-content",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.predefined_type(
"content",
"Content",
"computed::Content::normal()",
initial_specified_value="specified::Content::normal()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-content/#propdef-content",
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.predefined_type(
"counter-increment",
@ -20,7 +22,7 @@ ${helpers.predefined_type(
initial_value="Default::default()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-lists/#propdef-counter-increment",
servo_restyle_damage="rebuild_and_reflow"
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.predefined_type(
@ -29,5 +31,5 @@ ${helpers.predefined_type(
initial_value="Default::default()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-lists-3/#propdef-counter-reset",
servo_restyle_damage="rebuild_and_reflow"
servo_restyle_damage="rebuild_and_reflow",
)}

View file

@ -15,7 +15,7 @@ ${helpers.predefined_type(
flags="CREATES_STACKING_CONTEXT APPLIES_TO_PLACEHOLDER \
CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.csswg.org/css-color/#opacity",
servo_restyle_damage = "reflow_out_of_flow"
servo_restyle_damage = "reflow_out_of_flow",
)}
${helpers.predefined_type(
@ -31,13 +31,15 @@ ${helpers.predefined_type(
spec="https://drafts.csswg.org/css-backgrounds/#box-shadow",
)}
${helpers.predefined_type("clip",
"ClipRectOrAuto",
"computed::ClipRectOrAuto::auto()",
animation_value_type="ComputedValue",
boxed=True,
allow_quirks=True,
spec="https://drafts.fxtf.org/css-masking/#clip-property")}
${helpers.predefined_type(
"clip",
"ClipRectOrAuto",
"computed::ClipRectOrAuto::auto()",
animation_value_type="ComputedValue",
boxed=True,
allow_quirks=True,
spec="https://drafts.fxtf.org/css-masking/#clip-property",
)}
${helpers.predefined_type(
"filter",
@ -52,11 +54,14 @@ ${helpers.predefined_type(
spec="https://drafts.fxtf.org/filters/#propdef-filter",
)}
${helpers.single_keyword("mix-blend-mode",
"""normal multiply screen overlay darken lighten color-dodge
color-burn hard-light soft-light difference exclusion hue
saturation color luminosity""", gecko_constant_prefix="NS_STYLE_BLEND",
animation_value_type="discrete",
flags="CREATES_STACKING_CONTEXT",
gecko_pref="layout.css.mix-blend-mode.enabled",
spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode")}
${helpers.single_keyword(
"mix-blend-mode",
"""normal multiply screen overlay darken lighten color-dodge
color-burn hard-light soft-light difference exclusion hue
saturation color luminosity""",
gecko_constant_prefix="NS_STYLE_BLEND",
animation_value_type="discrete",
flags="CREATES_STACKING_CONTEXT",
gecko_pref="layout.css.mix-blend-mode.enabled",
spec="https://drafts.fxtf.org/compositing/#propdef-mix-blend-mode",
)}

View file

@ -40,15 +40,12 @@ ${helpers.single_keyword(
servo_restyle_damage="rebuild_and_reflow",
)}
// TODO(emilio): Should text-orientation be non-animatable? It affects the
// WritingMode value, but not the logical -> physical mapping of properties,
// which is the reason direction / writing-mode are non-animatable.
${helpers.single_keyword(
"text-orientation",
"mixed upright sideways",
extra_gecko_aliases="sideways-right=sideways",
products="gecko",
animation_value_type="discrete",
animation_value_type="none",
spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation",
)}

View file

@ -6,61 +6,81 @@
// SVG 1.1 (Second Edition)
// https://www.w3.org/TR/SVG/
<% data.new_style_struct("InheritedSVG",
inherited=True,
gecko_name="SVG") %>
<% data.new_style_struct("InheritedSVG", inherited=True, gecko_name="SVG") %>
// Section 10 - Text
${helpers.single_keyword("text-anchor",
"start middle end",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG/text.html#TextAnchorProperty")}
${helpers.single_keyword(
"text-anchor",
"start middle end",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG/text.html#TextAnchorProperty",
)}
// Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword("color-interpolation",
"srgb auto linearrgb",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty")}
${helpers.single_keyword(
"color-interpolation",
"srgb auto linearrgb",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty",
)}
${helpers.single_keyword("color-interpolation-filters", "linearrgb auto srgb",
products="gecko",
gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty")}
${helpers.single_keyword(
"color-interpolation-filters",
"linearrgb auto srgb",
products="gecko",
gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty",
)}
${helpers.predefined_type(
"fill", "SVGPaint",
"fill",
"SVGPaint",
"::values::computed::SVGPaint::black()",
products="gecko",
animation_value_type="IntermediateSVGPaint",
boxed=True,
spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint")}
${helpers.predefined_type("fill-opacity", "SVGOpacity", "Default::default()",
products="gecko", animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVG11/painting.html#FillOpacityProperty")}
${helpers.single_keyword("fill-rule", "nonzero evenodd",
gecko_enum_prefix="StyleFillRule",
products="gecko", animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#FillRuleProperty")}
${helpers.single_keyword("shape-rendering",
"auto optimizespeed crispedges geometricprecision",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty")}
spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint",
)}
${helpers.predefined_type(
"stroke", "SVGPaint",
"fill-opacity",
"SVGOpacity",
"Default::default()",
products="gecko",
animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVG11/painting.html#FillOpacityProperty",
)}
${helpers.single_keyword(
"fill-rule",
"nonzero evenodd",
gecko_enum_prefix="StyleFillRule",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#FillRuleProperty",
)}
${helpers.single_keyword(
"shape-rendering",
"auto optimizespeed crispedges geometricprecision",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty",
)}
${helpers.predefined_type(
"stroke",
"SVGPaint",
"Default::default()",
products="gecko",
animation_value_type="IntermediateSVGPaint",
boxed=True,
spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint")}
spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint",
)}
${helpers.predefined_type(
"stroke-width", "SVGWidth",
@ -70,23 +90,39 @@ ${helpers.predefined_type(
spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth",
)}
${helpers.single_keyword("stroke-linecap", "butt round square",
products="gecko", animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty")}
${helpers.single_keyword(
"stroke-linecap",
"butt round square",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty",
)}
${helpers.single_keyword("stroke-linejoin", "miter round bevel",
products="gecko", animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty")}
${helpers.single_keyword(
"stroke-linejoin",
"miter round bevel",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty",
)}
${helpers.predefined_type("stroke-miterlimit", "GreaterThanOrEqualToOneNumber",
"From::from(4.0)",
products="gecko",
animation_value_type="::values::computed::GreaterThanOrEqualToOneNumber",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty")}
${helpers.predefined_type(
"stroke-miterlimit",
"GreaterThanOrEqualToOneNumber",
"From::from(4.0)",
products="gecko",
animation_value_type="::values::computed::GreaterThanOrEqualToOneNumber",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty",
)}
${helpers.predefined_type("stroke-opacity", "SVGOpacity", "Default::default()",
products="gecko", animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty")}
${helpers.predefined_type(
"stroke-opacity",
"SVGOpacity",
"Default::default()",
products="gecko",
animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty",
)}
${helpers.predefined_type(
"stroke-dasharray",
@ -106,38 +142,59 @@ ${helpers.predefined_type(
)}
// Section 14 - Clipping, Masking and Compositing
${helpers.single_keyword("clip-rule", "nonzero evenodd",
products="gecko",
gecko_enum_prefix="StyleFillRule",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty")}
${helpers.single_keyword(
"clip-rule",
"nonzero evenodd",
products="gecko",
gecko_enum_prefix="StyleFillRule",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty",
)}
${helpers.predefined_type("marker-start", "url::UrlOrNone", "computed::url::UrlOrNone::none()",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}
${helpers.predefined_type(
"marker-start",
"url::UrlOrNone",
"computed::url::UrlOrNone::none()",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties",
)}
${helpers.predefined_type("marker-mid", "url::UrlOrNone", "computed::url::UrlOrNone::none()",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}
${helpers.predefined_type(
"marker-mid",
"url::UrlOrNone",
"computed::url::UrlOrNone::none()",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties",
)}
${helpers.predefined_type("marker-end", "url::UrlOrNone", "computed::url::UrlOrNone::none()",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}
${helpers.predefined_type(
"marker-end",
"url::UrlOrNone",
"computed::url::UrlOrNone::none()",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties",
)}
${helpers.predefined_type("paint-order", "SVGPaintOrder", "computed::SVGPaintOrder::normal()",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder")}
${helpers.predefined_type(
"paint-order",
"SVGPaintOrder",
"computed::SVGPaintOrder::normal()",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder",
)}
${helpers.predefined_type("-moz-context-properties",
"MozContextProperties",
initial_value=None,
vector=True,
need_index=True,
animation_value_type="none",
products="gecko",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)",
allow_empty=True)}
${helpers.predefined_type(
"-moz-context-properties",
"MozContextProperties",
initial_value=None,
vector=True,
need_index=True,
animation_value_type="none",
products="gecko",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)",
allow_empty=True,
)}

View file

@ -6,27 +6,40 @@
<% data.new_style_struct("InheritedTable", inherited=True, gecko_name="TableBorder") %>
${helpers.single_keyword("border-collapse", "separate collapse",
gecko_constant_prefix="NS_STYLE_BORDER",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-tables/#propdef-border-collapse",
servo_restyle_damage = "reflow")}
${helpers.single_keyword("empty-cells", "show hide",
gecko_constant_prefix="NS_STYLE_TABLE_EMPTY_CELLS",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-tables/#propdef-empty-cells",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.single_keyword("caption-side", "top bottom",
extra_gecko_values="right left top-outside bottom-outside",
needs_conversion="True",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-tables/#propdef-caption-side",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.single_keyword(
"border-collapse",
"separate collapse",
gecko_constant_prefix="NS_STYLE_BORDER",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-tables/#propdef-border-collapse",
servo_restyle_damage = "reflow",
)}
${helpers.predefined_type("border-spacing",
"BorderSpacing",
"computed::BorderSpacing::zero()",
animation_value_type="BorderSpacing",
boxed=True,
spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing",
servo_restyle_damage = "reflow")}
${helpers.single_keyword(
"empty-cells",
"show hide",
gecko_constant_prefix="NS_STYLE_TABLE_EMPTY_CELLS",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-tables/#propdef-empty-cells",
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.single_keyword(
"caption-side",
"top bottom",
extra_gecko_values="right left top-outside bottom-outside",
needs_conversion="True",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-tables/#propdef-caption-side",
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.predefined_type(
"border-spacing",
"BorderSpacing",
"computed::BorderSpacing::zero()",
animation_value_type="BorderSpacing",
boxed=True,
spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing",
servo_restyle_damage = "reflow",
)}

View file

@ -20,51 +20,68 @@ ${helpers.predefined_type(
// CSS Text Module Level 3
// TODO(pcwalton): `full-width`
${helpers.single_keyword("text-transform",
"none capitalize uppercase lowercase",
extra_gecko_values="full-width",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text/#propdef-text-transform",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.single_keyword(
"text-transform",
"none capitalize uppercase lowercase",
extra_gecko_values="full-width",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text/#propdef-text-transform",
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.single_keyword("hyphens", "manual none auto",
gecko_enum_prefix="StyleHyphens",
products="gecko", animation_value_type="discrete", extra_prefixes="moz",
spec="https://drafts.csswg.org/css-text/#propdef-hyphens")}
${helpers.single_keyword(
"hyphens",
"manual none auto",
gecko_enum_prefix="StyleHyphens",
products="gecko",
animation_value_type="discrete",
extra_prefixes="moz",
spec="https://drafts.csswg.org/css-text/#propdef-hyphens",
)}
// TODO: Support <percentage>
${helpers.single_keyword("-moz-text-size-adjust", "auto none",
gecko_constant_prefix="NS_STYLE_TEXT_SIZE_ADJUST",
gecko_ffi_name="mTextSizeAdjust",
products="gecko", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control",
alias="-webkit-text-size-adjust")}
${helpers.single_keyword(
"-moz-text-size-adjust",
"auto none",
gecko_constant_prefix="NS_STYLE_TEXT_SIZE_ADJUST",
gecko_ffi_name="mTextSizeAdjust",
products="gecko", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control",
alias="-webkit-text-size-adjust",
)}
${helpers.predefined_type("text-indent",
"LengthOrPercentage",
"computed::LengthOrPercentage::Length(computed::Length::new(0.))",
animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-text/#propdef-text-indent",
allow_quirks=True, servo_restyle_damage = "reflow")}
${helpers.predefined_type(
"text-indent",
"LengthOrPercentage",
"computed::LengthOrPercentage::Length(computed::Length::new(0.))",
animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-text/#propdef-text-indent",
allow_quirks=True,
servo_restyle_damage = "reflow",
)}
// Also known as "word-wrap" (which is more popular because of IE), but this is the preferred
// name per CSS-TEXT 6.2.
${helpers.single_keyword("overflow-wrap",
"normal break-word",
gecko_constant_prefix="NS_STYLE_OVERFLOWWRAP",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap",
alias="word-wrap",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.single_keyword(
"overflow-wrap",
"normal break-word",
gecko_constant_prefix="NS_STYLE_OVERFLOWWRAP",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap",
alias="word-wrap",
servo_restyle_damage="rebuild_and_reflow",
)}
// TODO(pcwalton): Support `word-break: keep-all` once we have better CJK support.
${helpers.single_keyword("word-break",
"normal break-all keep-all",
gecko_constant_prefix="NS_STYLE_WORDBREAK",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-text/#propdef-word-break",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.single_keyword(
"word-break",
"normal break-all keep-all",
gecko_constant_prefix="NS_STYLE_WORDBREAK",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-text/#propdef-word-break",
servo_restyle_damage="rebuild_and_reflow",
)}
// TODO(pcwalton): Support `text-justify: distribute`.
<%helpers:single_keyword
@ -106,39 +123,45 @@ ${helpers.single_keyword("word-break",
% endif
</%helpers:single_keyword>
${helpers.single_keyword("text-align-last",
"auto start end left right center justify",
products="gecko",
gecko_constant_prefix="NS_STYLE_TEXT_ALIGN",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-text/#propdef-text-align-last")}
${helpers.single_keyword(
"text-align-last",
"auto start end left right center justify",
products="gecko",
gecko_constant_prefix="NS_STYLE_TEXT_ALIGN",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-text/#propdef-text-align-last",
)}
// TODO make this a shorthand and implement text-align-last/text-align-all
//
// FIXME(emilio): This can't really be that complicated.
${helpers.predefined_type("text-align",
"TextAlign",
"computed::TextAlign::start()",
animation_value_type="discrete",
flags="APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text/#propdef-text-align",
servo_restyle_damage = "reflow")}
${helpers.predefined_type(
"text-align",
"TextAlign",
"computed::TextAlign::start()",
animation_value_type="discrete",
flags="APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text/#propdef-text-align",
servo_restyle_damage = "reflow",
)}
${helpers.predefined_type("letter-spacing",
"LetterSpacing",
"computed::LetterSpacing::normal()",
animation_value_type="ComputedValue",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.predefined_type(
"letter-spacing",
"LetterSpacing",
"computed::LetterSpacing::normal()",
animation_value_type="ComputedValue",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing",
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.predefined_type("word-spacing",
"WordSpacing",
"computed::WordSpacing::normal()",
animation_value_type="ComputedValue",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text/#propdef-word-spacing",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.predefined_type(
"word-spacing",
"WordSpacing",
"computed::WordSpacing::normal()",
animation_value_type="ComputedValue",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text/#propdef-word-spacing",
servo_restyle_damage="rebuild_and_reflow",
)}
<%helpers:single_keyword
name="white-space"
@ -267,47 +290,65 @@ ${helpers.predefined_type(
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color",
)}
${helpers.predefined_type("-webkit-text-stroke-width",
"BorderSideWidth",
"::values::computed::NonNegativeLength::new(0.)",
initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())",
computed_type="::values::computed::NonNegativeLength",
products="gecko",
gecko_pref="layout.css.prefixes.webkit",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width",
animation_value_type="discrete")}
${helpers.predefined_type(
"-webkit-text-stroke-width",
"BorderSideWidth",
"::values::computed::NonNegativeLength::new(0.)",
initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())",
computed_type="::values::computed::NonNegativeLength",
products="gecko",
gecko_pref="layout.css.prefixes.webkit",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width",
animation_value_type="discrete",
)}
// CSS Ruby Layout Module Level 1
// https://drafts.csswg.org/css-ruby/
${helpers.single_keyword("ruby-align", "space-around start center space-between",
products="gecko", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ruby/#ruby-align-property")}
${helpers.single_keyword(
"ruby-align",
"space-around start center space-between",
products="gecko",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ruby/#ruby-align-property",
)}
${helpers.single_keyword("ruby-position", "over under",
products="gecko", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ruby/#ruby-position-property")}
${helpers.single_keyword(
"ruby-position",
"over under",
products="gecko",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ruby/#ruby-position-property",
)}
// CSS Writing Modes Module Level 3
// https://drafts.csswg.org/css-writing-modes-3/
${helpers.single_keyword("text-combine-upright", "none all",
products="gecko", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright")}
${helpers.single_keyword(
"text-combine-upright",
"none all",
products="gecko",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-writing-modes-3/#text-combine-upright",
)}
// SVG 1.1: Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword("text-rendering",
"auto optimizespeed optimizelegibility geometricprecision",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.single_keyword(
"text-rendering",
"auto optimizespeed optimizelegibility geometricprecision",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/painting.html#TextRenderingProperty",
servo_restyle_damage="rebuild_and_reflow",
)}
// FIXME Firefox expects the initial value of this property to change depending
// on the value of the layout.css.control-characters.visible pref.
${helpers.single_keyword("-moz-control-character-visibility",
"hidden visible",
gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY",
gecko_ffi_name="mControlCharacterVisibility",
animation_value_type="none",
products="gecko",
spec="Nonstandard")}
${helpers.single_keyword(
"-moz-control-character-visibility",
"hidden visible",
gecko_constant_prefix="NS_STYLE_CONTROL_CHARACTER_VISIBILITY",
gecko_ffi_name="mControlCharacterVisibility",
animation_value_type="none",
products="gecko",
spec="Nonstandard",
)}

View file

@ -6,40 +6,56 @@
<% data.new_style_struct("InheritedUI", inherited=True, gecko_name="UI") %>
${helpers.predefined_type("cursor",
"Cursor",
"computed::Cursor::auto()",
initial_specified_value="specified::Cursor::auto()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ui/#cursor")}
${helpers.predefined_type(
"cursor",
"Cursor",
"computed::Cursor::auto()",
initial_specified_value="specified::Cursor::auto()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ui/#cursor",
)}
// NB: `pointer-events: auto` (and use of `pointer-events` in anything that isn't SVG, in fact)
// is nonstandard, slated for CSS4-UI.
// TODO(pcwalton): SVG-only values.
${helpers.single_keyword("pointer-events", "auto none", animation_value_type="discrete",
extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke all",
flags="APPLIES_TO_PLACEHOLDER",
spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty")}
${helpers.single_keyword(
"pointer-events",
"auto none",
animation_value_type="discrete",
extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke all",
flags="APPLIES_TO_PLACEHOLDER",
spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty",
)}
${helpers.single_keyword("-moz-user-input", "auto none",
products="gecko", gecko_ffi_name="mUserInput",
gecko_enum_prefix="StyleUserInput",
animation_value_type="discrete",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-input)")}
${helpers.single_keyword(
"-moz-user-input",
"auto none",
products="gecko",
gecko_ffi_name="mUserInput",
gecko_enum_prefix="StyleUserInput",
animation_value_type="discrete",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-input)",
)}
${helpers.single_keyword("-moz-user-modify", "read-only read-write write-only",
products="gecko", gecko_ffi_name="mUserModify",
gecko_enum_prefix="StyleUserModify",
needs_conversion=True,
animation_value_type="discrete",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-modify)")}
${helpers.single_keyword(
"-moz-user-modify",
"read-only read-write write-only",
products="gecko",
gecko_ffi_name="mUserModify",
gecko_enum_prefix="StyleUserModify",
needs_conversion=True,
animation_value_type="discrete",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-modify)",
)}
${helpers.single_keyword("-moz-user-focus",
"none ignore normal select-after select-before select-menu select-same select-all",
products="gecko", gecko_ffi_name="mUserFocus",
gecko_enum_prefix="StyleUserFocus",
animation_value_type="discrete",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-focus)")}
${helpers.single_keyword(
"-moz-user-focus",
"none ignore normal select-after select-before select-menu select-same select-all",
products="gecko", gecko_ffi_name="mUserFocus",
gecko_enum_prefix="StyleUserFocus",
animation_value_type="discrete",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-focus)",
)}
${helpers.predefined_type(
"caret-color",

View file

@ -40,25 +40,31 @@ ${helpers.single_keyword("list-style-position", "outside inside", animation_valu
)}
% endif
${helpers.predefined_type("list-style-image",
"url::ImageUrlOrNone",
initial_value="computed::url::ImageUrlOrNone::none()",
initial_specified_value="specified::url::ImageUrlOrNone::none()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-lists/#propdef-list-style-image",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.predefined_type(
"list-style-image",
"url::ImageUrlOrNone",
initial_value="computed::url::ImageUrlOrNone::none()",
initial_specified_value="specified::url::ImageUrlOrNone::none()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-lists/#propdef-list-style-image",
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.predefined_type("quotes",
"Quotes",
"computed::Quotes::get_initial_value()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-content/#propdef-quotes",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.predefined_type(
"quotes",
"Quotes",
"computed::Quotes::get_initial_value()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-content/#propdef-quotes",
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.predefined_type("-moz-image-region",
"ClipRectOrAuto",
"computed::ClipRectOrAuto::auto()",
animation_value_type="ComputedValue",
products="gecko",
boxed=True,
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)")}
${helpers.predefined_type(
"-moz-image-region",
"ClipRectOrAuto",
"computed::ClipRectOrAuto::auto()",
animation_value_type="ComputedValue",
products="gecko",
boxed=True,
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)",
)}

View file

@ -29,24 +29,34 @@ ${helpers.predefined_type(
spec="https://drafts.csswg.org/css-ui/#propdef-outline-style",
)}
${helpers.predefined_type("outline-width",
"BorderSideWidth",
"::values::computed::NonNegativeLength::new(3.)",
initial_specified_value="specified::BorderSideWidth::Medium",
computed_type="::values::computed::NonNegativeLength",
animation_value_type="NonNegativeLength",
spec="https://drafts.csswg.org/css-ui/#propdef-outline-width")}
${helpers.predefined_type(
"outline-width",
"BorderSideWidth",
"::values::computed::NonNegativeLength::new(3.)",
initial_specified_value="specified::BorderSideWidth::Medium",
computed_type="::values::computed::NonNegativeLength",
animation_value_type="NonNegativeLength",
spec="https://drafts.csswg.org/css-ui/#propdef-outline-width",
)}
// The -moz-outline-radius-* properties are non-standard and not on a standards track.
% for corner in ["topleft", "topright", "bottomright", "bottomleft"]:
${helpers.predefined_type("-moz-outline-radius-" + corner, "BorderCornerRadius",
${helpers.predefined_type(
"-moz-outline-radius-" + corner,
"BorderCornerRadius",
"computed::BorderCornerRadius::zero()",
products="gecko",
boxed=True,
animation_value_type="BorderCornerRadius",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)")}
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)",
)}
% endfor
${helpers.predefined_type("outline-offset", "Length", "::values::computed::Length::new(0.)",
products="servo gecko", animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-ui/#propdef-outline-offset")}
${helpers.predefined_type(
"outline-offset",
"Length",
"::values::computed::Length::new(0.)",
products="servo gecko",
animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-ui/#propdef-outline-offset",
)}

View file

@ -68,73 +68,93 @@ ${helpers.predefined_type(
// http://www.w3.org/TR/css3-flexbox/
// Flex container properties
${helpers.single_keyword("flex-direction", "row row-reverse column column-reverse",
spec="https://drafts.csswg.org/css-flexbox/#flex-direction-property",
extra_prefixes="webkit",
animation_value_type="discrete",
servo_restyle_damage = "reflow")}
${helpers.single_keyword(
"flex-direction",
"row row-reverse column column-reverse",
spec="https://drafts.csswg.org/css-flexbox/#flex-direction-property",
extra_prefixes="webkit",
animation_value_type="discrete",
servo_restyle_damage = "reflow",
)}
${helpers.single_keyword("flex-wrap", "nowrap wrap wrap-reverse",
spec="https://drafts.csswg.org/css-flexbox/#flex-wrap-property",
extra_prefixes="webkit",
animation_value_type="discrete",
servo_restyle_damage = "reflow")}
${helpers.single_keyword(
"flex-wrap",
"nowrap wrap wrap-reverse",
spec="https://drafts.csswg.org/css-flexbox/#flex-wrap-property",
extra_prefixes="webkit",
animation_value_type="discrete",
servo_restyle_damage = "reflow",
)}
% if product == "servo":
// FIXME: Update Servo to support the same Syntax as Gecko.
${helpers.single_keyword("justify-content", "flex-start stretch flex-end center space-between space-around",
extra_prefixes="webkit",
spec="https://drafts.csswg.org/css-align/#propdef-justify-content",
animation_value_type="discrete",
servo_restyle_damage = "reflow")}
${helpers.single_keyword(
"justify-content",
"flex-start stretch flex-end center space-between space-around",
extra_prefixes="webkit",
spec="https://drafts.csswg.org/css-align/#propdef-justify-content",
animation_value_type="discrete",
servo_restyle_damage = "reflow",
)}
% else:
${helpers.predefined_type(name="justify-content",
type="JustifyContent",
initial_value="specified::JustifyContent(specified::ContentDistribution::normal())",
spec="https://drafts.csswg.org/css-align/#propdef-justify-content",
extra_prefixes="webkit",
animation_value_type="discrete",
servo_restyle_damage = "reflow")}
${helpers.predefined_type(
"justify-content",
"JustifyContent",
"specified::JustifyContent(specified::ContentDistribution::normal())",
spec="https://drafts.csswg.org/css-align/#propdef-justify-content",
extra_prefixes="webkit",
animation_value_type="discrete",
servo_restyle_damage="reflow",
)}
% endif
% if product == "servo":
// FIXME: Update Servo to support the same Syntax as Gecko.
${helpers.single_keyword("align-content", "stretch flex-start flex-end center space-between space-around",
extra_prefixes="webkit",
spec="https://drafts.csswg.org/css-align/#propdef-align-content",
animation_value_type="discrete",
servo_restyle_damage = "reflow")}
${helpers.single_keyword(
"align-content",
"stretch flex-start flex-end center space-between space-around",
extra_prefixes="webkit",
spec="https://drafts.csswg.org/css-align/#propdef-align-content",
animation_value_type="discrete",
servo_restyle_damage="reflow",
)}
${helpers.single_keyword("align-items",
"stretch flex-start flex-end center baseline",
extra_prefixes="webkit",
spec="https://drafts.csswg.org/css-flexbox/#align-items-property",
animation_value_type="discrete",
servo_restyle_damage = "reflow")}
${helpers.single_keyword(
"align-items",
"stretch flex-start flex-end center baseline",
extra_prefixes="webkit",
spec="https://drafts.csswg.org/css-flexbox/#align-items-property",
animation_value_type="discrete",
servo_restyle_damage="reflow",
)}
% else:
${helpers.predefined_type(name="align-content",
type="AlignContent",
initial_value="specified::AlignContent(specified::ContentDistribution::normal())",
spec="https://drafts.csswg.org/css-align/#propdef-align-content",
extra_prefixes="webkit",
animation_value_type="discrete",
servo_restyle_damage = "reflow")}
${helpers.predefined_type(
"align-content",
"AlignContent",
"specified::AlignContent(specified::ContentDistribution::normal())",
spec="https://drafts.csswg.org/css-align/#propdef-align-content",
extra_prefixes="webkit",
animation_value_type="discrete",
servo_restyle_damage="reflow",
)}
${helpers.predefined_type(name="align-items",
type="AlignItems",
initial_value="specified::AlignItems::normal()",
spec="https://drafts.csswg.org/css-align/#propdef-align-items",
extra_prefixes="webkit",
animation_value_type="discrete",
servo_restyle_damage = "reflow")}
${helpers.predefined_type(
"align-items",
"AlignItems",
"specified::AlignItems::normal()",
spec="https://drafts.csswg.org/css-align/#propdef-align-items",
extra_prefixes="webkit",
animation_value_type="discrete",
servo_restyle_damage="reflow",
)}
#[cfg(feature = "gecko")]
impl_align_conversions!(::values::specified::align::AlignItems);
${helpers.predefined_type(
name="justify-items",
type="JustifyItems",
initial_value="computed::JustifyItems::legacy()",
"justify-items",
"JustifyItems",
"computed::JustifyItems::legacy()",
spec="https://drafts.csswg.org/css-align/#propdef-justify-items",
animation_value_type="discrete",
)}
@ -144,52 +164,69 @@ ${helpers.single_keyword("flex-wrap", "nowrap wrap wrap-reverse",
% endif
// Flex item properties
${helpers.predefined_type("flex-grow", "NonNegativeNumber",
"From::from(0.0)",
spec="https://drafts.csswg.org/css-flexbox/#flex-grow-property",
extra_prefixes="webkit",
animation_value_type="NonNegativeNumber",
servo_restyle_damage = "reflow")}
${helpers.predefined_type(
"flex-grow",
"NonNegativeNumber",
"From::from(0.0)",
spec="https://drafts.csswg.org/css-flexbox/#flex-grow-property",
extra_prefixes="webkit",
animation_value_type="NonNegativeNumber",
servo_restyle_damage="reflow",
)}
${helpers.predefined_type("flex-shrink", "NonNegativeNumber",
"From::from(1.0)",
spec="https://drafts.csswg.org/css-flexbox/#flex-shrink-property",
extra_prefixes="webkit",
animation_value_type="NonNegativeNumber",
servo_restyle_damage = "reflow")}
${helpers.predefined_type(
"flex-shrink",
"NonNegativeNumber",
"From::from(1.0)",
spec="https://drafts.csswg.org/css-flexbox/#flex-shrink-property",
extra_prefixes="webkit",
animation_value_type="NonNegativeNumber",
servo_restyle_damage = "reflow",
)}
// https://drafts.csswg.org/css-align/#align-self-property
% if product == "servo":
// FIXME: Update Servo to support the same syntax as Gecko.
${helpers.single_keyword("align-self", "auto stretch flex-start flex-end center baseline",
extra_prefixes="webkit",
spec="https://drafts.csswg.org/css-flexbox/#propdef-align-self",
animation_value_type="discrete",
servo_restyle_damage = "reflow")}
${helpers.single_keyword(
"align-self",
"auto stretch flex-start flex-end center baseline",
extra_prefixes="webkit",
spec="https://drafts.csswg.org/css-flexbox/#propdef-align-self",
animation_value_type="discrete",
servo_restyle_damage = "reflow",
)}
% else:
${helpers.predefined_type(name="align-self",
type="AlignSelf",
initial_value="specified::AlignSelf(specified::SelfAlignment::auto())",
spec="https://drafts.csswg.org/css-align/#align-self-property",
extra_prefixes="webkit",
animation_value_type="discrete")}
${helpers.predefined_type(
"align-self",
"AlignSelf",
"specified::AlignSelf(specified::SelfAlignment::auto())",
spec="https://drafts.csswg.org/css-align/#align-self-property",
extra_prefixes="webkit",
animation_value_type="discrete",
)}
${helpers.predefined_type(name="justify-self",
type="JustifySelf",
initial_value="specified::JustifySelf(specified::SelfAlignment::auto())",
spec="https://drafts.csswg.org/css-align/#justify-self-property",
animation_value_type="discrete")}
${helpers.predefined_type(
"justify-self",
"JustifySelf",
"specified::JustifySelf(specified::SelfAlignment::auto())",
spec="https://drafts.csswg.org/css-align/#justify-self-property",
animation_value_type="discrete",
)}
#[cfg(feature = "gecko")]
impl_align_conversions!(::values::specified::align::SelfAlignment);
% endif
// https://drafts.csswg.org/css-flexbox/#propdef-order
${helpers.predefined_type("order", "Integer", "0",
extra_prefixes="webkit",
animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-flexbox/#order-property",
servo_restyle_damage = "reflow")}
${helpers.predefined_type(
"order",
"Integer",
"0",
extra_prefixes="webkit",
animation_value_type="ComputedValue",
spec="https://drafts.csswg.org/css-flexbox/#order-property",
servo_restyle_damage = "reflow",
)}
${helpers.predefined_type(
"flex-basis",
@ -198,7 +235,7 @@ ${helpers.predefined_type(
spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
extra_prefixes="webkit",
animation_value_type="FlexBasis",
servo_restyle_damage = "reflow"
servo_restyle_damage = "reflow",
)}
% for (size, logical) in ALL_SIZES:
@ -228,7 +265,7 @@ ${helpers.predefined_type(
spec=spec % size,
animation_value_type="MozLength",
flags="GETCS_NEEDS_LAYOUT_FLUSH",
servo_restyle_damage="reflow"
servo_restyle_damage="reflow",
)}
// min-width, min-height, min-block-size, min-inline-size,
${helpers.predefined_type(
@ -241,7 +278,7 @@ ${helpers.predefined_type(
allow_quirks=not logical,
spec=spec % size,
animation_value_type="MozLength",
servo_restyle_damage = "reflow"
servo_restyle_damage="reflow",
)}
${helpers.predefined_type(
"max-%s" % size,
@ -253,7 +290,7 @@ ${helpers.predefined_type(
allow_quirks=not logical,
spec=spec % size,
animation_value_type="MaxLength",
servo_restyle_damage = "reflow"
servo_restyle_damage="reflow",
)}
% else:
// servo versions (no keyword support)
@ -266,7 +303,7 @@ ${helpers.predefined_type(
logical_group="size",
allow_quirks=not logical,
animation_value_type="ComputedValue", logical = logical,
servo_restyle_damage = "reflow",
servo_restyle_damage="reflow",
)}
${helpers.predefined_type(
"min-%s" % size,
@ -278,7 +315,7 @@ ${helpers.predefined_type(
animation_value_type="ComputedValue",
logical=logical,
allow_quirks=not logical,
servo_restyle_damage = "reflow",
servo_restyle_damage="reflow",
)}
${helpers.predefined_type(
"max-%s" % size,
@ -290,52 +327,64 @@ ${helpers.predefined_type(
animation_value_type="ComputedValue",
logical=logical,
allow_quirks=not logical,
servo_restyle_damage = "reflow",
servo_restyle_damage="reflow",
)}
% endif
% endfor
${helpers.single_keyword("box-sizing",
"content-box border-box",
extra_prefixes="moz:layout.css.prefixes.box-sizing webkit",
spec="https://drafts.csswg.org/css-ui/#propdef-box-sizing",
gecko_enum_prefix="StyleBoxSizing",
custom_consts={ "content-box": "Content", "border-box": "Border" },
animation_value_type="discrete",
servo_restyle_damage = "reflow")}
${helpers.single_keyword(
"box-sizing",
"content-box border-box",
extra_prefixes="moz:layout.css.prefixes.box-sizing webkit",
spec="https://drafts.csswg.org/css-ui/#propdef-box-sizing",
gecko_enum_prefix="StyleBoxSizing",
custom_consts={ "content-box": "Content", "border-box": "Border" },
animation_value_type="discrete",
servo_restyle_damage = "reflow",
)}
${helpers.single_keyword("object-fit", "fill contain cover none scale-down",
products="gecko", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-images/#propdef-object-fit")}
${helpers.single_keyword(
"object-fit",
"fill contain cover none scale-down",
products="gecko",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-images/#propdef-object-fit",
)}
${helpers.predefined_type("object-position",
"Position",
"computed::Position::zero()",
products="gecko",
boxed=True,
spec="https://drafts.csswg.org/css-images-3/#the-object-position",
animation_value_type="ComputedValue")}
${helpers.predefined_type(
"object-position",
"Position",
"computed::Position::zero()",
products="gecko",
boxed=True,
spec="https://drafts.csswg.org/css-images-3/#the-object-position",
animation_value_type="ComputedValue",
)}
% for kind in ["row", "column"]:
% for range in ["start", "end"]:
${helpers.predefined_type("grid-%s-%s" % (kind, range),
"GridLine",
"Default::default()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-%s" % (kind, range),
products="gecko",
boxed=True)}
${helpers.predefined_type(
"grid-%s-%s" % (kind, range),
"GridLine",
"Default::default()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-%s-%s" % (kind, range),
products="gecko",
boxed=True,
)}
% endfor
// NOTE: According to the spec, this should handle multiple values of `<track-size>`,
// but gecko supports only a single value
${helpers.predefined_type("grid-auto-%ss" % kind,
"TrackSize",
"Default::default()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind,
products="gecko",
boxed=True)}
${helpers.predefined_type(
"grid-auto-%ss" % kind,
"TrackSize",
"Default::default()",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-%ss" % kind,
products="gecko",
boxed=True,
)}
${helpers.predefined_type(
"grid-template-%ss" % kind,
@ -345,41 +394,49 @@ ${helpers.predefined_type("object-position",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-%ss" % kind,
boxed=True,
flags="GETCS_NEEDS_LAYOUT_FLUSH",
animation_value_type="discrete"
animation_value_type="discrete",
)}
% endfor
${helpers.predefined_type("grid-auto-flow",
"GridAutoFlow",
initial_value="computed::GridAutoFlow::row()",
products="gecko",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow")}
${helpers.predefined_type(
"grid-auto-flow",
"GridAutoFlow",
"computed::GridAutoFlow::row()",
products="gecko",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-auto-flow",
)}
${helpers.predefined_type("grid-template-areas",
"GridTemplateAreas",
initial_value="computed::GridTemplateAreas::none()",
products="gecko",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-areas")}
${helpers.predefined_type(
"grid-template-areas",
"GridTemplateAreas",
"computed::GridTemplateAreas::none()",
products="gecko",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-grid/#propdef-grid-template-areas",
)}
${helpers.predefined_type("column-gap",
"length::NonNegativeLengthOrPercentageOrNormal",
"Either::Second(Normal)",
alias="grid-column-gap" if product == "gecko" else "",
extra_prefixes="moz",
servo_pref="layout.columns.enabled",
spec="https://drafts.csswg.org/css-align-3/#propdef-column-gap",
animation_value_type="NonNegativeLengthOrPercentageOrNormal",
servo_restyle_damage = "reflow")}
${helpers.predefined_type(
"column-gap",
"length::NonNegativeLengthOrPercentageOrNormal",
"Either::Second(Normal)",
alias="grid-column-gap" if product == "gecko" else "",
extra_prefixes="moz",
servo_pref="layout.columns.enabled",
spec="https://drafts.csswg.org/css-align-3/#propdef-column-gap",
animation_value_type="NonNegativeLengthOrPercentageOrNormal",
servo_restyle_damage="reflow",
)}
// no need for -moz- prefixed alias for this property
${helpers.predefined_type("row-gap",
"length::NonNegativeLengthOrPercentageOrNormal",
"Either::Second(Normal)",
alias="grid-row-gap",
products="gecko",
spec="https://drafts.csswg.org/css-align-3/#propdef-row-gap",
animation_value_type="NonNegativeLengthOrPercentageOrNormal",
servo_restyle_damage = "reflow")}
${helpers.predefined_type(
"row-gap",
"length::NonNegativeLengthOrPercentageOrNormal",
"Either::Second(Normal)",
alias="grid-row-gap",
products="gecko",
spec="https://drafts.csswg.org/css-align-3/#propdef-row-gap",
animation_value_type="NonNegativeLengthOrPercentageOrNormal",
servo_restyle_damage="reflow",
)}

View file

@ -6,16 +6,22 @@
<% data.new_style_struct("SVG", inherited=False, gecko_name="SVGReset") %>
${helpers.single_keyword("dominant-baseline",
"""auto use-script no-change reset-size ideographic alphabetic hanging
mathematical central middle text-after-edge text-before-edge""",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/text.html#DominantBaselineProperty")}
${helpers.single_keyword(
"dominant-baseline",
"""auto use-script no-change reset-size ideographic alphabetic hanging
mathematical central middle text-after-edge text-before-edge""",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVG11/text.html#DominantBaselineProperty",
)}
${helpers.single_keyword("vector-effect", "none non-scaling-stroke",
products="gecko", animation_value_type="discrete",
spec="https://www.w3.org/TR/SVGTiny12/painting.html#VectorEffectProperty")}
${helpers.single_keyword(
"vector-effect",
"none non-scaling-stroke",
products="gecko",
animation_value_type="discrete",
spec="https://www.w3.org/TR/SVGTiny12/painting.html#VectorEffectProperty",
)}
// Section 13 - Gradients and Patterns
@ -28,10 +34,14 @@ ${helpers.predefined_type(
spec="https://www.w3.org/TR/SVGTiny12/painting.html#StopColorProperty",
)}
${helpers.predefined_type("stop-opacity", "Opacity", "1.0",
products="gecko",
animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVGTiny12/painting.html#propdef-stop-opacity")}
${helpers.predefined_type(
"stop-opacity",
"Opacity",
"1.0",
products="gecko",
animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVGTiny12/painting.html#propdef-stop-opacity",
)}
// Section 15 - Filter Effects
@ -44,9 +54,14 @@ ${helpers.predefined_type(
spec="https://www.w3.org/TR/SVG/filters.html#FloodColorProperty",
)}
${helpers.predefined_type("flood-opacity", "Opacity",
"1.0", products="gecko", animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVG/filters.html#FloodOpacityProperty")}
${helpers.predefined_type(
"flood-opacity",
"Opacity",
"1.0",
products="gecko",
animation_value_type="ComputedValue",
spec="https://www.w3.org/TR/SVG/filters.html#FloodOpacityProperty",
)}
${helpers.predefined_type(
"lighting-color",
@ -59,9 +74,13 @@ ${helpers.predefined_type(
// CSS Masking Module Level 1
// https://drafts.fxtf.org/css-masking
${helpers.single_keyword("mask-type", "luminance alpha",
products="gecko", animation_value_type="discrete",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-type")}
${helpers.single_keyword(
"mask-type",
"luminance alpha",
products="gecko",
animation_value_type="discrete",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-type",
)}
${helpers.predefined_type(
"clip-path",
@ -74,12 +93,14 @@ ${helpers.predefined_type(
spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path",
)}
${helpers.single_keyword("mask-mode",
"match-source alpha luminance",
vector=True,
products="gecko",
animation_value_type="discrete",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-mode")}
${helpers.single_keyword(
"mask-mode",
"match-source alpha luminance",
vector=True,
products="gecko",
animation_value_type="discrete",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-mode",
)}
${helpers.predefined_type(
"mask-repeat",
@ -97,9 +118,9 @@ ${helpers.predefined_type(
${helpers.predefined_type(
"mask-position-" + axis,
"position::" + direction + "Position",
"computed::LengthOrPercentage::zero()",
products="gecko",
extra_prefixes="webkit",
initial_value="computed::LengthOrPercentage::zero()",
initial_specified_value="specified::PositionComponent::Center",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position",
animation_value_type="ComputedValue",
@ -147,20 +168,25 @@ ${helpers.predefined_type(
vector_animation_type="repeatable_list",
)}
${helpers.single_keyword("mask-composite",
"add subtract intersect exclude",
vector=True,
products="gecko",
extra_prefixes="webkit",
animation_value_type="discrete",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite")}
${helpers.single_keyword(
"mask-composite",
"add subtract intersect exclude",
vector=True,
products="gecko",
extra_prefixes="webkit",
animation_value_type="discrete",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite",
)}
${helpers.predefined_type("mask-image", "ImageLayer",
initial_value="Either::First(None_)",
${helpers.predefined_type(
"mask-image",
"ImageLayer",
"Either::First(None_)",
initial_specified_value="Either::First(None_)",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image",
vector=True,
products="gecko",
extra_prefixes="webkit",
animation_value_type="discrete",
flags="CREATES_STACKING_CONTEXT")}
flags="CREATES_STACKING_CONTEXT",
)}

View file

@ -6,15 +6,21 @@
<% data.new_style_struct("Table", inherited=False) %>
${helpers.single_keyword("table-layout", "auto fixed",
gecko_ffi_name="mLayoutStrategy", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-tables/#propdef-table-layout",
servo_restyle_damage = "reflow")}
${helpers.single_keyword(
"table-layout",
"auto fixed",
gecko_ffi_name="mLayoutStrategy",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-tables/#propdef-table-layout",
servo_restyle_damage="reflow",
)}
${helpers.predefined_type("-x-span",
"XSpan",
"computed::XSpan(1)",
products="gecko",
spec="Internal-only (for `<col span>` pres attr)",
animation_value_type="none",
enabled_in="")}
${helpers.predefined_type(
"-x-span",
"XSpan",
"computed::XSpan(1)",
products="gecko",
spec="Internal-only (for `<col span>` pres attr)",
animation_value_type="none",
enabled_in="",
)}

View file

@ -5,43 +5,55 @@
<%namespace name="helpers" file="/helpers.mako.rs" />
<% from data import Method %>
<% data.new_style_struct("Text",
inherited=False,
gecko_name="TextReset",
additional_methods=[Method("has_underline", "bool"),
Method("has_overline", "bool"),
Method("has_line_through", "bool")]) %>
<% data.new_style_struct(
"Text",
inherited=False,
gecko_name="TextReset",
additional_methods=[
Method("has_underline", "bool"),
Method("has_overline", "bool"),
Method("has_line_through", "bool"),
]
) %>
${helpers.predefined_type("text-overflow",
"TextOverflow",
"computed::TextOverflow::get_initial_value()",
animation_value_type="discrete",
boxed=True,
flags="APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-ui/#propdef-text-overflow",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.predefined_type(
"text-overflow",
"TextOverflow",
"computed::TextOverflow::get_initial_value()",
animation_value_type="discrete",
boxed=True,
flags="APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-ui/#propdef-text-overflow",
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.single_keyword("unicode-bidi",
"normal embed isolate bidi-override isolate-override plaintext",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-writing-modes/#propdef-unicode-bidi",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.single_keyword(
"unicode-bidi",
"normal embed isolate bidi-override isolate-override plaintext",
animation_value_type="none",
spec="https://drafts.csswg.org/css-writing-modes/#propdef-unicode-bidi",
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.predefined_type("text-decoration-line",
"TextDecorationLine",
"specified::TextDecorationLine::none()",
initial_specified_value="specified::TextDecorationLine::none()",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-line",
servo_restyle_damage="rebuild_and_reflow")}
${helpers.predefined_type(
"text-decoration-line",
"TextDecorationLine",
"specified::TextDecorationLine::none()",
initial_specified_value="specified::TextDecorationLine::none()",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-line",
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.single_keyword("text-decoration-style",
"solid double dotted dashed wavy -moz-none",
products="gecko",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-style")}
${helpers.single_keyword(
"text-decoration-style",
"solid double dotted dashed wavy -moz-none",
products="gecko",
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-style",
)}
${helpers.predefined_type(
"text-decoration-color",
@ -64,4 +76,5 @@ ${helpers.predefined_type(
products="gecko",
flags="APPLIES_TO_FIRST_LETTER",
gecko_pref="layout.css.initial-letter.enabled",
spec="https://drafts.csswg.org/css-inline/#sizing-drop-initials")}
spec="https://drafts.csswg.org/css-inline/#sizing-drop-initials",
)}

View file

@ -11,10 +11,14 @@
// TODO spec says that UAs should not support this
// we should probably remove from gecko (https://bugzilla.mozilla.org/show_bug.cgi?id=1328331)
${helpers.single_keyword("ime-mode", "auto normal active disabled inactive",
products="gecko", gecko_ffi_name="mIMEMode",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ui/#input-method-editor")}
${helpers.single_keyword(
"ime-mode",
"auto normal active disabled inactive",
products="gecko",
gecko_ffi_name="mIMEMode",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ui/#input-method-editor",
)}
${helpers.single_keyword(
"scrollbar-width",
@ -27,30 +31,40 @@ ${helpers.single_keyword(
spec="https://drafts.csswg.org/css-scrollbars-1/#scrollbar-width"
)}
${helpers.single_keyword("-moz-user-select", "auto text none all element elements" +
" toggle tri-state -moz-all -moz-text",
products="gecko",
alias="-webkit-user-select",
gecko_ffi_name="mUserSelect",
gecko_enum_prefix="StyleUserSelect",
gecko_strip_moz_prefix=False,
aliases="-moz-none=none",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select")}
${helpers.single_keyword(
"-moz-user-select",
"auto text none all element elements toggle tri-state -moz-all -moz-text",
products="gecko",
alias="-webkit-user-select",
gecko_ffi_name="mUserSelect",
gecko_enum_prefix="StyleUserSelect",
gecko_strip_moz_prefix=False,
aliases="-moz-none=none",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select",
)}
// TODO(emilio): This probably should be hidden from content.
${helpers.single_keyword("-moz-window-dragging", "default drag no-drag", products="gecko",
gecko_ffi_name="mWindowDragging",
gecko_enum_prefix="StyleWindowDragging",
animation_value_type="discrete",
spec="None (Nonstandard Firefox-only property)")}
${helpers.single_keyword(
"-moz-window-dragging",
"default drag no-drag",
products="gecko",
gecko_ffi_name="mWindowDragging",
gecko_enum_prefix="StyleWindowDragging",
animation_value_type="discrete",
spec="None (Nonstandard Firefox-only property)",
)}
${helpers.single_keyword("-moz-window-shadow", "none default menu tooltip sheet", products="gecko",
gecko_ffi_name="mWindowShadow",
gecko_constant_prefix="NS_STYLE_WINDOW_SHADOW",
animation_value_type="discrete",
enabled_in="chrome",
spec="None (Nonstandard internal property)")}
${helpers.single_keyword(
"-moz-window-shadow",
"none default menu tooltip sheet",
products="gecko",
gecko_ffi_name="mWindowShadow",
gecko_constant_prefix="NS_STYLE_WINDOW_SHADOW",
animation_value_type="discrete",
enabled_in="chrome",
spec="None (Nonstandard internal property)",
)}
${helpers.predefined_type(
"-moz-window-opacity",
@ -89,9 +103,11 @@ ${helpers.predefined_type(
)}
// TODO(emilio): Probably also should be hidden from content.
${helpers.predefined_type("-moz-force-broken-image-icon",
"MozForceBrokenImageIcon",
"computed::MozForceBrokenImageIcon::false_value()",
animation_value_type="discrete",
products="gecko",
spec="None (Nonstandard Firefox-only property)")}
${helpers.predefined_type(
"-moz-force-broken-image-icon",
"MozForceBrokenImageIcon",
"computed::MozForceBrokenImageIcon::false_value()",
animation_value_type="discrete",
products="gecko",
spec="None (Nonstandard Firefox-only property)",
)}

View file

@ -8,51 +8,79 @@
// Non-standard properties that Gecko uses for XUL elements.
<% data.new_style_struct("XUL", inherited=False) %>
${helpers.single_keyword("-moz-box-align", "stretch start center baseline end",
products="gecko", gecko_ffi_name="mBoxAlign",
gecko_enum_prefix="StyleBoxAlign",
animation_value_type="discrete",
alias="-webkit-box-align",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-align)")}
${helpers.single_keyword(
"-moz-box-align",
"stretch start center baseline end",
products="gecko",
gecko_ffi_name="mBoxAlign",
gecko_enum_prefix="StyleBoxAlign",
animation_value_type="discrete",
alias="-webkit-box-align",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-align)",
)}
${helpers.single_keyword("-moz-box-direction", "normal reverse",
products="gecko", gecko_ffi_name="mBoxDirection",
gecko_enum_prefix="StyleBoxDirection",
animation_value_type="discrete",
alias="-webkit-box-direction",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-direction)")}
${helpers.single_keyword(
"-moz-box-direction",
"normal reverse",
products="gecko",
gecko_ffi_name="mBoxDirection",
gecko_enum_prefix="StyleBoxDirection",
animation_value_type="discrete",
alias="-webkit-box-direction",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-direction)",
)}
${helpers.predefined_type("-moz-box-flex", "NonNegativeNumber", "From::from(0.)",
products="gecko", gecko_ffi_name="mBoxFlex",
animation_value_type="NonNegativeNumber",
alias="-webkit-box-flex",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-flex)")}
${helpers.predefined_type(
"-moz-box-flex",
"NonNegativeNumber",
"From::from(0.)",
products="gecko",
gecko_ffi_name="mBoxFlex",
animation_value_type="NonNegativeNumber",
alias="-webkit-box-flex",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-flex)",
)}
${helpers.single_keyword("-moz-box-orient", "horizontal vertical",
products="gecko", gecko_ffi_name="mBoxOrient",
extra_gecko_aliases="inline-axis=horizontal block-axis=vertical",
gecko_enum_prefix="StyleBoxOrient",
animation_value_type="discrete",
alias="-webkit-box-orient",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-orient)")}
${helpers.single_keyword(
"-moz-box-orient",
"horizontal vertical",
products="gecko",
gecko_ffi_name="mBoxOrient",
extra_gecko_aliases="inline-axis=horizontal block-axis=vertical",
gecko_enum_prefix="StyleBoxOrient",
animation_value_type="discrete",
alias="-webkit-box-orient",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-orient)",
)}
${helpers.single_keyword("-moz-box-pack", "start center end justify",
products="gecko", gecko_ffi_name="mBoxPack",
gecko_enum_prefix="StyleBoxPack",
animation_value_type="discrete",
alias="-webkit-box-pack",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-pack)")}
${helpers.single_keyword(
"-moz-box-pack",
"start center end justify",
products="gecko", gecko_ffi_name="mBoxPack",
gecko_enum_prefix="StyleBoxPack",
animation_value_type="discrete",
alias="-webkit-box-pack",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-pack)",
)}
${helpers.single_keyword("-moz-stack-sizing", "stretch-to-fit ignore ignore-horizontal ignore-vertical",
products="gecko", gecko_ffi_name="mStackSizing",
gecko_enum_prefix="StyleStackSizing",
animation_value_type="discrete",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-stack-sizing)")}
${helpers.single_keyword(
"-moz-stack-sizing",
"stretch-to-fit ignore ignore-horizontal ignore-vertical",
products="gecko",
gecko_ffi_name="mStackSizing",
gecko_enum_prefix="StyleStackSizing",
animation_value_type="discrete",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-stack-sizing)",
)}
${helpers.predefined_type("-moz-box-ordinal-group", "Integer", "0",
parse_method="parse_non_negative",
products="gecko",
alias="-webkit-box-ordinal-group",
gecko_ffi_name="mBoxOrdinal",
animation_value_type="discrete",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-box-ordinal-group)")}
${helpers.predefined_type(
"-moz-box-ordinal-group",
"Integer",
"0",
parse_method="parse_non_negative",
products="gecko",
alias="-webkit-box-ordinal-group",
gecko_ffi_name="mBoxOrdinal",
animation_value_type="discrete",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-box-ordinal-group)",
)}

View file

@ -425,6 +425,10 @@ pub mod animated_properties {
#[derive(Clone, Copy, Debug)]
pub struct NonCustomPropertyId(usize);
/// The length of all the non-custom properties.
pub const NON_CUSTOM_PROPERTY_ID_COUNT: usize =
${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())};
% if product == "gecko":
#[allow(dead_code)]
unsafe fn static_assert_nscsspropertyid() {
@ -435,6 +439,11 @@ unsafe fn static_assert_nscsspropertyid() {
% endif
impl NonCustomPropertyId {
/// Returns the underlying index, used for use counter.
pub fn bit(self) -> usize {
self.0
}
#[cfg(feature = "gecko")]
#[inline]
fn to_nscsspropertyid(self) -> nsCSSPropertyID {
@ -450,7 +459,7 @@ impl NonCustomPropertyId {
if prop < 0 {
return Err(());
}
if prop >= ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} {
if prop >= NON_CUSTOM_PROPERTY_ID_COUNT as i32 {
return Err(());
}
// unsafe: guaranteed by static_assert_nscsspropertyid above.
@ -460,7 +469,7 @@ impl NonCustomPropertyId {
/// Get the property name.
#[inline]
pub fn name(self) -> &'static str {
static MAP: [&'static str; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}] = [
static MAP: [&'static str; NON_CUSTOM_PROPERTY_ID_COUNT] = [
% for property in data.longhands + data.shorthands + data.all_aliases():
"${property.name}",
% endfor
@ -635,7 +644,7 @@ impl NonCustomPropertyId {
PropertyId::Shorthand(transmute((self.0 - ${len(data.longhands)}) as u16))
}
}
assert!(self.0 < ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())});
assert!(self.0 < NON_CUSTOM_PROPERTY_ID_COUNT);
let alias_id: AliasId = unsafe {
transmute((self.0 - ${len(data.longhands) + len(data.shorthands)}) as u16)
};
@ -671,7 +680,7 @@ impl From<AliasId> for NonCustomPropertyId {
/// A set of all properties
#[derive(Clone, PartialEq)]
pub struct NonCustomPropertyIdSet {
storage: [u32; (${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} - 1 + 32) / 32]
storage: [u32; (NON_CUSTOM_PROPERTY_ID_COUNT - 1 + 32) / 32]
}
impl NonCustomPropertyIdSet {
@ -1554,6 +1563,7 @@ impl UnparsedValue {
ParsingMode::DEFAULT,
quirks_mode,
None,
None,
);
let mut input = ParserInput::new(&css);
@ -1853,7 +1863,8 @@ impl PropertyId {
}
}
fn non_custom_id(&self) -> Option<NonCustomPropertyId> {
/// Returns the `NonCustomPropertyId` corresponding to this property id.
pub fn non_custom_id(&self) -> Option<NonCustomPropertyId> {
Some(match *self {
PropertyId::Custom(_) => return None,
PropertyId::Shorthand(shorthand_id) => shorthand_id.into(),
@ -2198,7 +2209,7 @@ impl PropertyDeclaration {
// FIXME: fully implement https://github.com/w3c/csswg-drafts/issues/774
// before adding skip_whitespace here.
// This probably affects some test results.
let value = match input.try(|i| CSSWideKeyword::parse(i)) {
let value = match input.try(CSSWideKeyword::parse) {
Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword),
Err(()) => match ::custom_properties::SpecifiedValue::parse(input) {
Ok(value) => DeclaredValueOwned::Value(value),
@ -2212,12 +2223,12 @@ impl PropertyDeclaration {
name: property_name,
value,
}));
Ok(())
return Ok(());
}
PropertyId::LonghandAlias(id, _) |
PropertyId::Longhand(id) => {
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
input.try(|i| CSSWideKeyword::parse(i)).map(|keyword| {
input.try(CSSWideKeyword::parse).map(|keyword| {
PropertyDeclaration::CSSWideKeyword(
WideKeywordDeclaration { id, keyword },
)
@ -2253,12 +2264,12 @@ impl PropertyDeclaration {
})
}).map(|declaration| {
declarations.push(declaration)
})
})?;
}
PropertyId::ShorthandAlias(id, _) |
PropertyId::Shorthand(id) => {
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
if let Ok(keyword) = input.try(|i| CSSWideKeyword::parse(i)) {
if let Ok(keyword) = input.try(CSSWideKeyword::parse) {
if id == ShorthandId::All {
declarations.all_shorthand = AllShorthand::CSSWideKeyword(keyword)
} else {
@ -2271,51 +2282,55 @@ impl PropertyDeclaration {
))
}
}
Ok(())
} else {
input.look_for_var_functions();
// Not using parse_entirely here: each ${shorthand.ident}::parse_into function
// needs to do so *before* pushing to `declarations`.
id.parse_into(declarations, context, input).or_else(|err| {
while let Ok(_) = input.next() {} // Look for var() after the error.
if input.seen_var_functions() {
input.reset(&start);
let (first_token_type, css) =
::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
StyleParseErrorKind::new_invalid(
non_custom_id.unwrap().name(),
e,
)
})?;
let unparsed = Arc::new(UnparsedValue {
css: css.into_owned(),
first_token_type: first_token_type,
url_data: context.url_data.clone(),
from_shorthand: Some(id),
});
if id == ShorthandId::All {
declarations.all_shorthand = AllShorthand::WithVariables(unparsed)
} else {
for id in id.longhands() {
declarations.push(
PropertyDeclaration::WithVariables(VariableDeclaration {
id,
value: unparsed.clone(),
})
)
}
}
Ok(())
} else {
Err(StyleParseErrorKind::new_invalid(
if !input.seen_var_functions() {
return Err(StyleParseErrorKind::new_invalid(
non_custom_id.unwrap().name(),
err,
))
));
}
})
input.reset(&start);
let (first_token_type, css) =
::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
StyleParseErrorKind::new_invalid(
non_custom_id.unwrap().name(),
e,
)
})?;
let unparsed = Arc::new(UnparsedValue {
css: css.into_owned(),
first_token_type: first_token_type,
url_data: context.url_data.clone(),
from_shorthand: Some(id),
});
if id == ShorthandId::All {
declarations.all_shorthand = AllShorthand::WithVariables(unparsed)
} else {
for id in id.longhands() {
declarations.push(
PropertyDeclaration::WithVariables(VariableDeclaration {
id,
value: unparsed.clone(),
})
)
}
}
Ok(())
})?;
}
}
}
debug_assert!(non_custom_id.is_some(), "Custom properties should've returned earlier");
if let Some(use_counters) = context.use_counters {
use_counters.non_custom_properties.record(non_custom_id.unwrap());
}
Ok(())
}
}

View file

@ -6,11 +6,14 @@
#![deny(missing_docs)]
use Atom;
use cssparser::{Parser as CssParser, ParserInput};
use element_state::ElementState;
use selectors::parser::SelectorList;
use std::fmt::{self, Debug, Write};
use style_traits::{CssWriter, ParseError, ToCss};
use stylesheets::{Namespaces, Origin, UrlExtraData};
use values::serialize_atom_identifier;
/// A convenient alias for the type that represents an attribute value used for
/// selector parser implementation.
@ -172,27 +175,49 @@ impl<T> PerPseudoElementMap<T> {
}
/// Values for the :dir() pseudo class
///
/// "ltr" and "rtl" values are normalized to lowercase.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
pub enum Direction {
/// left-to-right semantic directionality
pub struct Direction(pub Atom);
/// Horizontal values for the :dir() pseudo class
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum HorizontalDirection {
/// :dir(ltr)
Ltr,
/// right-to-left semantic directionality
/// :dir(rtl)
Rtl,
/// Some other provided directionality value
///
/// TODO(emilio): If we atomize we can then unbox in NonTSPseudoClass.
Other(Box<str>),
}
impl Direction {
/// Parse a direction value.
pub fn parse<'i, 't>(parser: &mut CssParser<'i, 't>) -> Result<Self, ParseError<'i>> {
let ident = parser.expect_ident()?;
Ok(match_ignore_ascii_case! { &ident,
"rtl" => Direction::Rtl,
"ltr" => Direction::Ltr,
_ => Direction::Other(Box::from(ident.as_ref())),
})
Ok(Direction(match_ignore_ascii_case! { &ident,
"rtl" => atom!("rtl"),
"ltr" => atom!("ltr"),
_ => Atom::from(ident.as_ref()),
}))
}
/// Convert this Direction into a HorizontalDirection, if applicable
pub fn as_horizontal_direction(&self) -> Option<HorizontalDirection> {
if self.0 == atom!("ltr") {
Some(HorizontalDirection::Ltr)
} else if self.0 == atom!("rtl") {
Some(HorizontalDirection::Rtl)
} else {
None
}
}
/// Gets the element state relevant to this :dir() selector.
pub fn element_state(&self) -> ElementState {
match self.as_horizontal_direction() {
Some(HorizontalDirection::Ltr) => ElementState::IN_LTR_STATE,
Some(HorizontalDirection::Rtl) => ElementState::IN_RTL_STATE,
None => ElementState::empty(),
}
}
}
@ -201,12 +226,6 @@ impl ToCss for Direction {
where
W: Write,
{
let dir_str = match *self {
Direction::Rtl => "rtl",
Direction::Ltr => "ltr",
// FIXME: This should be escaped as an identifier; see #19231
Direction::Other(ref other) => other,
};
dest.write_str(dir_str)
serialize_atom_identifier(&self.0, dest)
}
}

View file

@ -135,6 +135,10 @@ impl PseudoElement {
self.is_before() || self.is_after()
}
/// Whether this is an unknown ::-webkit- pseudo-element.
#[inline]
pub fn is_unknown_webkit_pseudo_element(&self) -> bool { false }
/// Whether this pseudo-element is the ::before pseudo.
#[inline]
pub fn is_before(&self) -> bool {
@ -284,8 +288,8 @@ impl PseudoElement {
}
}
/// The type used for storing pseudo-class string arguments.
pub type PseudoClassStringArg = Box<str>;
/// The type used for storing `:lang` arguments.
pub type Lang = Box<str>;
/// A non tree-structural pseudo-class.
/// See https://drafts.csswg.org/selectors-4/#structural-pseudos
@ -302,7 +306,7 @@ pub enum NonTSPseudoClass {
Fullscreen,
Hover,
Indeterminate,
Lang(PseudoClassStringArg),
Lang(Lang),
Link,
PlaceholderShown,
ReadWrite,

View file

@ -219,6 +219,7 @@ impl Keyframe {
ParsingMode::DEFAULT,
parent_stylesheet_contents.quirks_mode,
None,
None,
);
context.namespaces = Some(&*namespaces);
let mut input = ParserInput::new(css);

View file

@ -264,6 +264,7 @@ impl CssRule {
ParsingMode::DEFAULT,
parent_stylesheet_contents.quirks_mode,
None,
None,
);
let mut input = ParserInput::new(css);

View file

@ -24,6 +24,7 @@ use stylesheets::loader::StylesheetLoader;
use stylesheets::rule_parser::{State, TopLevelRuleParser};
use stylesheets::rules_iterator::{EffectiveRules, EffectiveRulesIterator};
use stylesheets::rules_iterator::{NestedRuleIterationCondition, RulesIterator};
use use_counters::UseCounters;
/// This structure holds the user-agent and user stylesheets.
pub struct UserAgentStylesheets {
@ -78,6 +79,7 @@ impl StylesheetContents {
error_reporter: Option<&ParseErrorReporter>,
quirks_mode: QuirksMode,
line_number_offset: u32,
use_counters: Option<&UseCounters>,
) -> Self {
let namespaces = RwLock::new(Namespaces::default());
let (rules, source_map_url, source_url) = Stylesheet::parse_rules(
@ -90,6 +92,7 @@ impl StylesheetContents {
error_reporter,
quirks_mode,
line_number_offset,
use_counters,
);
Self {
@ -315,6 +318,8 @@ impl Stylesheet {
line_number_offset: u32,
) {
let namespaces = RwLock::new(Namespaces::default());
// FIXME: Consider adding use counters to Servo?
let (rules, source_map_url, source_url) = Self::parse_rules(
css,
&url_data,
@ -325,6 +330,7 @@ impl Stylesheet {
error_reporter,
existing.contents.quirks_mode,
line_number_offset,
/* use_counters = */ None,
);
*existing.contents.url_data.write() = url_data;
@ -350,6 +356,7 @@ impl Stylesheet {
error_reporter: Option<&ParseErrorReporter>,
quirks_mode: QuirksMode,
line_number_offset: u32,
use_counters: Option<&UseCounters>,
) -> (Vec<CssRule>, Option<String>, Option<String>) {
let mut rules = Vec::new();
let mut input = ParserInput::new_with_line_number_offset(css, line_number_offset);
@ -362,6 +369,7 @@ impl Stylesheet {
ParsingMode::DEFAULT,
quirks_mode,
error_reporter,
use_counters,
);
let rule_parser = TopLevelRuleParser {
@ -421,6 +429,7 @@ impl Stylesheet {
quirks_mode: QuirksMode,
line_number_offset: u32,
) -> Self {
// FIXME: Consider adding use counters to Servo?
let contents = StylesheetContents::from_str(
css,
url_data,
@ -430,6 +439,7 @@ impl Stylesheet {
error_reporter,
quirks_mode,
line_number_offset,
/* use_counters = */ None,
);
Stylesheet {

View file

@ -24,11 +24,11 @@ use properties::{self, CascadeMode, ComputedValues};
use properties::{AnimationRules, PropertyDeclarationBlock};
use rule_cache::{RuleCache, RuleCacheConditions};
use rule_tree::{CascadeLevel, RuleTree, ShadowCascadeOrder, StrongRuleNode, StyleSource};
use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry};
use selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, SelectorMapEntry};
use selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap};
use selectors::NthIndexCache;
use selectors::attr::{CaseSensitivity, NamespaceConstraint};
use selectors::bloom::{BloomFilter, NonCountingBloomFilter};
use selectors::bloom::BloomFilter;
use selectors::matching::{matches_selector, ElementSelectorFlags, MatchingContext, MatchingMode};
use selectors::matching::VisitedHandlingMode;
use selectors::parser::{AncestorHashes, Combinator, Component, Selector};
@ -1206,7 +1206,7 @@ impl Stylist {
// to add some sort of AuthorScoped cascade level or something.
if matches_author_rules {
if let Some(shadow) = rule_hash_target.shadow_root() {
if let Some(map) = shadow.style_data().host_rules(pseudo_element) {
if let Some(map) = shadow.style_data().and_then(|data| data.host_rules(pseudo_element)) {
context.with_shadow_host(Some(rule_hash_target), |context| {
map.get_all_matching_rules(
element,
@ -1233,8 +1233,7 @@ impl Stylist {
for slot in slots.iter().rev() {
let shadow = slot.containing_shadow().unwrap();
let styles = shadow.style_data();
if let Some(map) = styles.slotted_rules(pseudo_element) {
if let Some(map) = shadow.style_data().and_then(|data| data.slotted_rules(pseudo_element)) {
context.with_shadow_host(Some(shadow.host()), |context| {
map.get_all_matching_rules(
element,
@ -1253,7 +1252,7 @@ impl Stylist {
if let Some(containing_shadow) = rule_hash_target.containing_shadow() {
let cascade_data = containing_shadow.style_data();
let host = containing_shadow.host();
if let Some(map) = cascade_data.normal_rules(pseudo_element) {
if let Some(map) = cascade_data.and_then(|data| data.normal_rules(pseudo_element)) {
context.with_shadow_host(Some(host), |context| {
map.get_all_matching_rules(
element,
@ -1283,6 +1282,11 @@ impl Stylist {
//
// See: https://github.com/w3c/svgwg/issues/505
//
// FIXME(emilio, bug 1487259): We now do after bug 1483882, we
// should jump out of the <svg:use> shadow tree chain now.
//
// Unless the used node is cross-doc, I guess, in which case doc
// rules are probably ok...
let host_is_svg_use =
host.is_svg_element() &&
host.local_name() == &*local_name!("use");
@ -1392,8 +1396,7 @@ impl Stylist {
CaseSensitivity::CaseSensitive => {},
}
let hash = id.get_hash();
self.any_applicable_rule_data(element, |data| data.mapped_ids.might_contain_hash(hash))
self.any_applicable_rule_data(element, |data| data.mapped_ids.contains(id))
}
/// Returns the registered `@keyframes` animation for the specified name.
@ -1431,11 +1434,15 @@ impl Stylist {
// [2]: https://github.com/w3c/csswg-drafts/issues/1995
// [3]: https://bugzil.la/1458189
if let Some(shadow) = element.shadow_root() {
try_find_in!(shadow.style_data());
if let Some(data) = shadow.style_data() {
try_find_in!(data);
}
}
if let Some(shadow) = element.containing_shadow() {
try_find_in!(shadow.style_data());
if let Some(data) = shadow.style_data() {
try_find_in!(data);
}
} else {
try_find_in!(self.cascade_data.author);
}
@ -1745,11 +1752,9 @@ struct StylistSelectorVisitor<'a> {
passed_rightmost_selector: bool,
/// The filter with all the id's getting referenced from rightmost
/// selectors.
mapped_ids: &'a mut NonCountingBloomFilter,
mapped_ids: &'a mut PrecomputedHashSet<Atom>,
/// The filter with the local names of attributes there are selectors for.
attribute_dependencies: &'a mut NonCountingBloomFilter,
/// Whether there's any attribute selector for the [style] attribute.
style_attribute_dependency: &'a mut bool,
attribute_dependencies: &'a mut PrecomputedHashSet<LocalName>,
/// All the states selectors in the page reference.
state_dependencies: &'a mut ElementState,
/// All the document states selectors in the page reference.
@ -1814,13 +1819,8 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
name: &LocalName,
lower_name: &LocalName,
) -> bool {
if *lower_name == local_name!("style") {
*self.style_attribute_dependency = true;
} else {
self.attribute_dependencies.insert_hash(name.get_hash());
self.attribute_dependencies
.insert_hash(lower_name.get_hash());
}
self.attribute_dependencies.insert(name.clone());
self.attribute_dependencies.insert(lower_name.clone());
true
}
@ -1846,7 +1846,7 @@ impl<'a> SelectorVisitor for StylistSelectorVisitor<'a> {
//
// NOTE(emilio): See the comment regarding on when this may
// break in visit_complex_selector.
self.mapped_ids.insert_hash(id.get_hash());
self.mapped_ids.insert(id.clone());
},
_ => {},
}
@ -1878,7 +1878,9 @@ impl ElementAndPseudoRules {
pseudo_element: Option<&PseudoElement>,
quirks_mode: QuirksMode,
) -> Result<(), FailedAllocationError> {
debug_assert!(pseudo_element.map_or(true, |pseudo| !pseudo.is_precomputed()));
debug_assert!(pseudo_element.map_or(true, |pseudo| {
!pseudo.is_precomputed() && !pseudo.is_unknown_webkit_pseudo_element()
}));
let map = match pseudo_element {
None => &mut self.element_map,
@ -1944,18 +1946,9 @@ pub struct CascadeData {
/// The attribute local names that appear in attribute selectors. Used
/// to avoid taking element snapshots when an irrelevant attribute changes.
/// (We don't bother storing the namespace, since namespaced attributes
/// are rare.)
#[ignore_malloc_size_of = "just an array"]
attribute_dependencies: NonCountingBloomFilter,
/// Whether `"style"` appears in an attribute selector. This is not common,
/// and by tracking this explicitly, we can avoid taking an element snapshot
/// in the common case of style=""` changing due to modifying
/// `element.style`. (We could track this in `attribute_dependencies`, like
/// all other attributes, but we should probably not risk incorrectly
/// returning `true` for `"style"` just due to a hash collision.)
style_attribute_dependency: bool,
/// (We don't bother storing the namespace, since namespaced attributes are
/// rare.)
attribute_dependencies: PrecomputedHashSet<LocalName>,
/// The element state bits that are relied on by selectors. Like
/// `attribute_dependencies`, this is used to avoid taking element snapshots
@ -1971,8 +1964,7 @@ pub struct CascadeData {
/// hence in our selector maps). Used to determine when sharing styles is
/// safe: we disallow style sharing for elements whose id matches this
/// filter, and hence might be in one of our selector maps.
#[ignore_malloc_size_of = "just an array"]
mapped_ids: NonCountingBloomFilter,
mapped_ids: PrecomputedHashSet<Atom>,
/// Selectors that require explicit cache revalidation (i.e. which depend
/// on state that is not otherwise visible to the cache, like attributes or
@ -2009,11 +2001,10 @@ impl CascadeData {
host_rules: None,
slotted_rules: None,
invalidation_map: InvalidationMap::new(),
attribute_dependencies: NonCountingBloomFilter::new(),
style_attribute_dependency: false,
attribute_dependencies: PrecomputedHashSet::default(),
state_dependencies: ElementState::empty(),
document_state_dependencies: DocumentState::empty(),
mapped_ids: NonCountingBloomFilter::new(),
mapped_ids: PrecomputedHashSet::default(),
selectors_for_cache_revalidation: SelectorMap::new(),
animations: Default::default(),
extra_data: ExtraStyleData::default(),
@ -2078,13 +2069,9 @@ impl CascadeData {
/// selector of some rule.
#[inline]
pub fn might_have_attribute_dependency(&self, local_name: &LocalName) -> bool {
if *local_name == local_name!("style") {
return self.style_attribute_dependency;
}
self.attribute_dependencies
.might_contain_hash(local_name.get_hash())
self.attribute_dependencies.contains(local_name)
}
#[inline]
fn normal_rules(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
self.normal_rules.rules(pseudo)
@ -2191,6 +2178,9 @@ impl CascadeData {
));
continue;
}
if pseudo.is_unknown_webkit_pseudo_element() {
continue;
}
}
let hashes = AncestorHashes::new(&selector, quirks_mode);
@ -2208,7 +2198,6 @@ impl CascadeData {
needs_revalidation: false,
passed_rightmost_selector: false,
attribute_dependencies: &mut self.attribute_dependencies,
style_attribute_dependency: &mut self.style_attribute_dependency,
state_dependencies: &mut self.state_dependencies,
document_state_dependencies: &mut self.document_state_dependencies,
mapped_ids: &mut self.mapped_ids,
@ -2418,7 +2407,6 @@ impl CascadeData {
self.clear_cascade_data();
self.invalidation_map.clear();
self.attribute_dependencies.clear();
self.style_attribute_dependency = false;
self.state_dependencies = ElementState::empty();
self.document_state_dependencies = DocumentState::empty();
self.mapped_ids.clear();
@ -2514,16 +2502,14 @@ impl Rule {
/// A function to be able to test the revalidation stuff.
pub fn needs_revalidation_for_testing(s: &Selector<SelectorImpl>) -> bool {
let mut attribute_dependencies = NonCountingBloomFilter::new();
let mut mapped_ids = NonCountingBloomFilter::new();
let mut style_attribute_dependency = false;
let mut attribute_dependencies = Default::default();
let mut mapped_ids = Default::default();
let mut state_dependencies = ElementState::empty();
let mut document_state_dependencies = DocumentState::empty();
let mut visitor = StylistSelectorVisitor {
needs_revalidation: false,
passed_rightmost_selector: false,
attribute_dependencies: &mut attribute_dependencies,
style_attribute_dependency: &mut style_attribute_dependency,
state_dependencies: &mut state_dependencies,
document_state_dependencies: &mut document_state_dependencies,
mapped_ids: &mut mapped_ids,

View file

@ -0,0 +1,87 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Various stuff for CSS property use counters.
#[cfg(feature = "gecko")]
use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
use properties::{NonCustomPropertyId, NON_CUSTOM_PROPERTY_ID_COUNT};
use std::cell::Cell;
#[cfg(target_pointer_width = "64")]
const BITS_PER_ENTRY: usize = 64;
#[cfg(target_pointer_width = "32")]
const BITS_PER_ENTRY: usize = 32;
/// One bit per each non-custom CSS property.
#[derive(Default)]
pub struct NonCustomPropertyUseCounters {
storage: [Cell<usize>; (NON_CUSTOM_PROPERTY_ID_COUNT - 1 + BITS_PER_ENTRY) / BITS_PER_ENTRY],
}
impl NonCustomPropertyUseCounters {
/// Returns the bucket a given property belongs in, and the bitmask for that
/// property.
#[inline(always)]
fn bucket_and_pattern(id: NonCustomPropertyId) -> (usize, usize) {
let bit = id.bit();
let bucket = bit / BITS_PER_ENTRY;
let bit_in_bucket = bit % BITS_PER_ENTRY;
(bucket, 1 << bit_in_bucket)
}
/// Record that a given non-custom property ID has been parsed.
#[inline]
pub fn record(&self, id: NonCustomPropertyId) {
let (bucket, pattern) = Self::bucket_and_pattern(id);
let bucket = &self.storage[bucket];
bucket.set(bucket.get() | pattern)
}
/// Returns whether a given non-custom property ID has been recorded
/// earlier.
#[inline]
pub fn recorded(&self, id: NonCustomPropertyId) -> bool {
let (bucket, pattern) = Self::bucket_and_pattern(id);
self.storage[bucket].get() & pattern != 0
}
/// Merge `other` into `self`.
#[inline]
fn merge(&self, other: &Self) {
for (bucket, other_bucket) in self.storage.iter().zip(other.storage.iter()) {
bucket.set(bucket.get() | other_bucket.get())
}
}
}
/// The use-counter data related to a given document we want to store.
#[derive(Default)]
pub struct UseCounters {
/// The counters for non-custom properties that have been parsed in the
/// document's stylesheets.
pub non_custom_properties: NonCustomPropertyUseCounters,
}
impl UseCounters {
/// Merge the use counters.
///
/// Used for parallel parsing, where we parse off-main-thread.
#[inline]
pub fn merge(&self, other: &Self) {
self.non_custom_properties.merge(&other.non_custom_properties)
}
}
#[cfg(feature = "gecko")]
unsafe impl HasFFI for UseCounters {
type FFIType = ::gecko_bindings::structs::StyleUseCounters;
}
#[cfg(feature = "gecko")]
unsafe impl HasSimpleFFI for UseCounters {}
#[cfg(feature = "gecko")]
unsafe impl HasBoxFFI for UseCounters {}

View file

@ -81,3 +81,19 @@ impl ToAnimatedZero for BorderCornerRadius {
Err(())
}
}
impl BorderRadius {
/// Returns whether all the values are `0px`.
pub fn all_zero(&self) -> bool {
fn all(corner: &BorderCornerRadius) -> bool {
fn is_zero(l: &LengthOrPercentage) -> bool {
*l == LengthOrPercentage::zero()
}
is_zero(corner.0.width()) && is_zero(corner.0.height())
}
all(&self.top_left) &&
all(&self.top_right) &&
all(&self.bottom_left) &&
all(&self.bottom_right)
}
}

View file

@ -65,6 +65,7 @@ pub use self::length::{NonNegativeLengthOrPercentage, NonNegativeLengthOrPercent
pub use self::list::Quotes;
#[cfg(feature = "gecko")]
pub use self::list::ListStyleType;
pub use self::motion::OffsetPath;
pub use self::outline::OutlineStyle;
pub use self::percentage::{Percentage, NonNegativePercentage};
pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex};
@ -100,6 +101,7 @@ pub mod gecko;
pub mod image;
pub mod length;
pub mod list;
pub mod motion;
pub mod outline;
pub mod percentage;
pub mod position;

View file

@ -0,0 +1,10 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Computed types for CSS values that are related to motion path.
/// A computed offset-path. The computed value is as specified value.
///
/// https://drafts.fxtf.org/motion-1/#offset-path-property
pub use values::specified::motion::OffsetPath as OffsetPath;

View file

@ -12,6 +12,7 @@ use values::distance::{ComputeSquaredDistance, SquaredDistance};
use values::generics::border::BorderRadius;
use values::generics::position::Position;
use values::generics::rect::Rect;
use values::specified::SVGPathData;
/// A clipping shape, for `clip-path`.
pub type ClippingShape<BasicShape, Url> = ShapeSource<BasicShape, GeometryBox, Url>;
@ -54,6 +55,9 @@ pub enum ShapeSource<BasicShape, ReferenceBox, ImageOrUrl> {
#[animation(error)]
Box(ReferenceBox),
#[animation(error)]
#[css(function)]
Path(Path),
#[animation(error)]
None,
}
@ -113,16 +117,23 @@ pub enum ShapeRadius<LengthOrPercentage> {
/// A generic type for representing the `polygon()` function
///
/// <https://drafts.csswg.org/css-shapes/#funcdef-polygon>
#[css(function)]
#[css(comma, function)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue)]
ToComputedValue, ToCss)]
pub struct Polygon<LengthOrPercentage> {
/// The filling rule for a polygon.
#[css(skip_if = "fill_is_default")]
pub fill: FillRule,
/// A collection of (x, y) coordinates to draw the polygon.
pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>,
#[css(iterable)]
pub coordinates: Vec<PolygonCoord<LengthOrPercentage>>,
}
/// Coordinates for Polygon.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo,
ToComputedValue, ToCss)]
pub struct PolygonCoord<LengthOrPercentage>(pub LengthOrPercentage, pub LengthOrPercentage);
// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
// NOTE: Basic shapes spec says that these are the only two values, however
// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
@ -131,11 +142,25 @@ pub struct Polygon<LengthOrPercentage> {
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
#[repr(u8)]
pub enum FillRule {
Nonzero,
Evenodd,
}
/// The path function defined in css-shape-2.
///
/// https://drafts.csswg.org/css-shapes-2/#funcdef-path
#[css(comma)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub struct Path {
/// The filling rule for the svg path.
#[css(skip_if = "fill_is_default")]
pub fill: FillRule,
/// The svg path data.
pub path: SVGPathData,
}
// FIXME(nox): Implement ComputeSquaredDistance for T types and stop
// using PartialEq here, this will let us derive this impl.
impl<B, T, U> ComputeSquaredDistance for ShapeSource<B, T, U>
@ -203,7 +228,7 @@ where
.iter()
.zip(other.coordinates.iter())
.map(|(this, other)| {
Ok((
Ok(PolygonCoord(
this.0.animate(&other.0, procedure)?,
this.1.animate(&other.1, procedure)?,
))
@ -239,34 +264,14 @@ where
}
}
impl<L: ToCss> ToCss for Polygon<L> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
dest.write_str("polygon(")?;
if self.fill != FillRule::default() {
self.fill.to_css(dest)?;
dest.write_str(", ")?;
}
for (i, coord) in self.coordinates.iter().enumerate() {
if i > 0 {
dest.write_str(", ")?;
}
coord.0.to_css(dest)?;
dest.write_str(" ")?;
coord.1.to_css(dest)?;
}
dest.write_str(")")
}
}
impl Default for FillRule {
#[inline]
fn default() -> Self {
FillRule::Nonzero
}
}
#[inline]
fn fill_is_default(fill: &FillRule) -> bool {
*fill == FillRule::default()
}

View file

@ -14,9 +14,11 @@ use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use values::computed::Percentage;
use values::generics::basic_shape as generic;
use values::generics::basic_shape::{FillRule, GeometryBox, ShapeBox, ShapeSource};
use values::generics::basic_shape::{FillRule, GeometryBox, Path, PolygonCoord};
use values::generics::basic_shape::{ShapeBox, ShapeSource};
use values::generics::rect::Rect;
use values::specified::LengthOrPercentage;
use values::specified::SVGPathData;
use values::specified::border::BorderRadius;
use values::specified::image::Image;
use values::specified::position::{HorizontalPosition, Position, PositionComponent};
@ -47,12 +49,42 @@ pub type ShapeRadius = generic::ShapeRadius<LengthOrPercentage>;
/// The specified value of `Polygon`
pub type Polygon = generic::Polygon<LengthOrPercentage>;
impl<ReferenceBox, ImageOrUrl> Parse for ShapeSource<BasicShape, ReferenceBox, ImageOrUrl>
impl Parse for ClippingShape {
#[inline]
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
// |clip-path:path()| is a chrome-only property value support for now. `path()` is
// defined in css-shape-2, but the spec is not stable enough, and we haven't decided
// to make it public yet. However, it has some benefits for the front-end, so we
// implement it.
if context.chrome_rules_enabled() {
if let Ok(p) = input.try(|i| Path::parse(context, i)) {
return Ok(ShapeSource::Path(p));
}
}
Self::parse_internal(context, input)
}
}
impl Parse for FloatAreaShape {
#[inline]
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Self::parse_internal(context, input)
}
}
impl<ReferenceBox, ImageOrUrl> ShapeSource<BasicShape, ReferenceBox, ImageOrUrl>
where
ReferenceBox: Parse,
ImageOrUrl: Parse,
{
fn parse<'i, 't>(
/// The internal parser for ShapeSource.
fn parse_internal<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
@ -381,7 +413,7 @@ impl Polygon {
.unwrap_or_default();
let buf = input.parse_comma_separated(|i| {
Ok((
Ok(PolygonCoord(
LengthOrPercentage::parse(context, i)?,
LengthOrPercentage::parse(context, i)?,
))
@ -393,3 +425,29 @@ impl Polygon {
})
}
}
impl Parse for Path {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
input.expect_function_matching("path")?;
input.parse_nested_block(|i| Self::parse_function_arguments(context, i))
}
}
impl Path {
/// Parse the inner arguments of a `path` function.
fn parse_function_arguments<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let fill = input.try(|i| -> Result<_, ParseError> {
let fill = FillRule::parse(i)?;
i.expect_comma()?;
Ok(fill)
}).unwrap_or_default();
let path = SVGPathData::parse(context, input)?;
Ok(Path { fill, path })
}
}

View file

@ -57,8 +57,8 @@ fn moz_box_display_values_enabled(context: &ParserContext) -> bool {
/// Also, when you change this from Gecko you may need to regenerate the
/// C++-side bindings (see components/style/cbindgen.toml).
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq,
SpecifiedValueInfo, ToComputedValue, ToCss)]
#[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, Parse,
PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[repr(u8)]
pub enum Display {

View file

@ -58,6 +58,7 @@ pub use self::length::{NonNegativeLengthOrPercentage, NonNegativeLengthOrPercent
pub use self::list::Quotes;
#[cfg(feature = "gecko")]
pub use self::list::ListStyleType;
pub use self::motion::OffsetPath;
pub use self::outline::OutlineStyle;
pub use self::rect::LengthOrNumberRect;
pub use self::resolution::Resolution;
@ -67,6 +68,7 @@ pub use self::position::{PositionComponent, ZIndex};
pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::svg::MozContextProperties;
pub use self::svg_path::SVGPathData;
pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize, TextAlign};
pub use self::text::{TextEmphasisPosition, TextEmphasisStyle};
@ -100,6 +102,7 @@ pub mod grid;
pub mod image;
pub mod length;
pub mod list;
pub mod motion;
pub mod outline;
pub mod percentage;
pub mod position;
@ -107,6 +110,7 @@ pub mod rect;
pub mod resolution;
pub mod source_size_list;
pub mod svg;
pub mod svg_path;
pub mod table;
pub mod text;
pub mod time;

View file

@ -0,0 +1,61 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Specified types for CSS values that are related to motion path.
use cssparser::Parser;
use parser::{Parse, ParserContext};
use style_traits::{ParseError, StyleParseErrorKind};
use values::specified::SVGPathData;
/// The offset-path value.
///
/// https://drafts.fxtf.org/motion-1/#offset-path-property
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)]
pub enum OffsetPath {
// We could merge SVGPathData into ShapeSource, so we could reuse them. However,
// we don't want to support other value for offset-path, so use SVGPathData only for now.
/// Path value for path(<string>).
#[css(function)]
Path(SVGPathData),
/// None value.
None,
// Bug 1186329: Implement ray(), <basic-shape>, <geometry-box>, and <url>.
}
impl OffsetPath {
/// Return None.
#[inline]
pub fn none() -> Self {
OffsetPath::None
}
}
impl Parse for OffsetPath {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<Self, ParseError<'i>> {
// Parse none.
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(OffsetPath::none());
}
// Parse possible functions.
let location = input.current_source_location();
let function = input.expect_function()?.clone();
input.parse_nested_block(move |i| {
match_ignore_ascii_case! { &function,
// Bug 1186329: Implement the parser for ray(), <basic-shape>, <geometry-box>,
// and <url>.
"path" => SVGPathData::parse(context, i).map(OffsetPath::Path),
_ => {
Err(location.new_custom_error(
StyleParseErrorKind::UnexpectedFunction(function.clone())
))
},
}
})
}
}

View file

@ -0,0 +1,515 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Specified types for SVG Path.
use cssparser::Parser;
use parser::{Parse, ParserContext};
use std::fmt::{self, Write};
use std::iter::{Cloned, Peekable};
use std::slice;
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use style_traits::values::SequenceWriter;
use values::CSSFloat;
/// The SVG path data.
///
/// https://www.w3.org/TR/SVG11/paths.html#PathData
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)]
pub struct SVGPathData(Box<[PathCommand]>);
impl SVGPathData {
/// Return SVGPathData by a slice of PathCommand.
#[inline]
pub fn new(cmd: Box<[PathCommand]>) -> Self {
debug_assert!(!cmd.is_empty());
SVGPathData(cmd)
}
/// Get the array of PathCommand.
#[inline]
pub fn commands(&self) -> &[PathCommand] {
debug_assert!(!self.0.is_empty());
&self.0
}
}
impl ToCss for SVGPathData {
#[inline]
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: fmt::Write
{
dest.write_char('"')?;
{
let mut writer = SequenceWriter::new(dest, " ");
for command in self.0.iter() {
writer.item(command)?;
}
}
dest.write_char('"')
}
}
impl Parse for SVGPathData {
// We cannot use cssparser::Parser to parse a SVG path string because the spec wants to make
// the SVG path string as compact as possible. (i.e. The whitespaces may be dropped.)
// e.g. "M100 200L100 200" is a valid SVG path string. If we use tokenizer, the first ident
// is "M100", instead of "M", and this is not correct. Therefore, we use a Peekable
// str::Char iterator to check each character.
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<Self, ParseError<'i>> {
let location = input.current_source_location();
let path_string = input.expect_string()?.as_ref();
if path_string.is_empty() {
// Treat an empty string as invalid, so we will not set it.
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
// Parse the svg path string as multiple sub-paths.
let mut path_parser = PathParser::new(path_string);
while skip_wsp(&mut path_parser.chars) {
if path_parser.parse_subpath().is_err() {
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
}
Ok(SVGPathData::new(path_parser.path.into_boxed_slice()))
}
}
/// The SVG path command.
/// The fields of these commands are self-explanatory, so we skip the documents.
/// Note: the index of the control points, e.g. control1, control2, are mapping to the control
/// points of the Bézier curve in the spec.
///
/// https://www.w3.org/TR/SVG11/paths.html#PathData
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo)]
#[allow(missing_docs)]
#[repr(C, u8)]
pub enum PathCommand {
/// The unknown type.
/// https://www.w3.org/TR/SVG/paths.html#__svg__SVGPathSeg__PATHSEG_UNKNOWN
Unknown,
/// The "moveto" command.
MoveTo { point: CoordPair, absolute: bool },
/// The "lineto" command.
LineTo { point: CoordPair, absolute: bool },
/// The horizontal "lineto" command.
HorizontalLineTo { x: CSSFloat, absolute: bool },
/// The vertical "lineto" command.
VerticalLineTo { y: CSSFloat, absolute: bool },
/// The cubic Bézier curve command.
CurveTo { control1: CoordPair, control2: CoordPair, point: CoordPair, absolute: bool },
/// The smooth curve command.
SmoothCurveTo { control2: CoordPair, point: CoordPair, absolute: bool },
/// The quadratic Bézier curve command.
QuadBezierCurveTo { control1: CoordPair, point: CoordPair, absolute: bool },
/// The smooth quadratic Bézier curve command.
SmoothQuadBezierCurveTo { point: CoordPair, absolute: bool },
/// The elliptical arc curve command.
EllipticalArc {
rx: CSSFloat,
ry: CSSFloat,
angle: CSSFloat,
large_arc_flag: bool,
sweep_flag: bool,
point: CoordPair,
absolute: bool
},
/// The "closepath" command.
ClosePath,
}
impl ToCss for PathCommand {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: fmt::Write
{
use self::PathCommand::*;
match *self {
Unknown => dest.write_char('X'),
ClosePath => dest.write_char('Z'),
MoveTo { point, absolute } => {
dest.write_char(if absolute { 'M' } else { 'm' })?;
dest.write_char(' ')?;
point.to_css(dest)
}
LineTo { point, absolute } => {
dest.write_char(if absolute { 'L' } else { 'l' })?;
dest.write_char(' ')?;
point.to_css(dest)
}
CurveTo { control1, control2, point, absolute } => {
dest.write_char(if absolute { 'C' } else { 'c' })?;
dest.write_char(' ')?;
control1.to_css(dest)?;
dest.write_char(' ')?;
control2.to_css(dest)?;
dest.write_char(' ')?;
point.to_css(dest)
},
QuadBezierCurveTo { control1, point, absolute } => {
dest.write_char(if absolute { 'Q' } else { 'q' })?;
dest.write_char(' ')?;
control1.to_css(dest)?;
dest.write_char(' ')?;
point.to_css(dest)
},
EllipticalArc { rx, ry, angle, large_arc_flag, sweep_flag, point, absolute } => {
dest.write_char(if absolute { 'A' } else { 'a' })?;
dest.write_char(' ')?;
rx.to_css(dest)?;
dest.write_char(' ')?;
ry.to_css(dest)?;
dest.write_char(' ')?;
angle.to_css(dest)?;
dest.write_char(' ')?;
(large_arc_flag as i32).to_css(dest)?;
dest.write_char(' ')?;
(sweep_flag as i32).to_css(dest)?;
dest.write_char(' ')?;
point.to_css(dest)
},
HorizontalLineTo { x, absolute } => {
dest.write_char(if absolute { 'H' } else { 'h' })?;
dest.write_char(' ')?;
x.to_css(dest)
},
VerticalLineTo { y, absolute } => {
dest.write_char(if absolute { 'V' } else { 'v' })?;
dest.write_char(' ')?;
y.to_css(dest)
},
SmoothCurveTo { control2, point, absolute } => {
dest.write_char(if absolute { 'S' } else { 's' })?;
dest.write_char(' ')?;
control2.to_css(dest)?;
dest.write_char(' ')?;
point.to_css(dest)
},
SmoothQuadBezierCurveTo { point, absolute } => {
dest.write_char(if absolute { 'T' } else { 't' })?;
dest.write_char(' ')?;
point.to_css(dest)
},
}
}
}
/// The path coord type.
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
#[repr(C)]
pub struct CoordPair(CSSFloat, CSSFloat);
impl CoordPair {
/// Create a CoordPair.
#[inline]
pub fn new(x: CSSFloat, y: CSSFloat) -> Self {
CoordPair(x, y)
}
}
/// SVG Path parser.
struct PathParser<'a> {
chars: Peekable<Cloned<slice::Iter<'a, u8>>>,
path: Vec<PathCommand>,
}
macro_rules! parse_arguments {
(
$parser:ident,
$abs:ident,
$enum:ident,
[ $para:ident => $func:ident $(, $other_para:ident => $other_func:ident)* ]
) => {
{
loop {
let $para = $func(&mut $parser.chars)?;
$(
skip_comma_wsp(&mut $parser.chars);
let $other_para = $other_func(&mut $parser.chars)?;
)*
$parser.path.push(PathCommand::$enum { $para $(, $other_para)*, $abs });
// End of string or the next character is a possible new command.
if !skip_wsp(&mut $parser.chars) ||
$parser.chars.peek().map_or(true, |c| c.is_ascii_alphabetic()) {
break;
}
skip_comma_wsp(&mut $parser.chars);
}
Ok(())
}
}
}
impl<'a> PathParser<'a> {
/// Return a PathParser.
#[inline]
fn new(string: &'a str) -> Self {
PathParser {
chars: string.as_bytes().iter().cloned().peekable(),
path: Vec::new(),
}
}
/// Parse a sub-path.
fn parse_subpath(&mut self) -> Result<(), ()> {
// Handle "moveto" Command first. If there is no "moveto", this is not a valid sub-path
// (i.e. not a valid moveto-drawto-command-group).
self.parse_moveto()?;
// Handle other commands.
loop {
skip_wsp(&mut self.chars);
if self.chars.peek().map_or(true, |&m| m == b'M' || m == b'm') {
break;
}
match self.chars.next() {
Some(command) => {
let abs = command.is_ascii_uppercase();
macro_rules! parse_command {
( $($($p:pat)|+ => $parse_func:ident,)* ) => {
match command {
$(
$($p)|+ => {
skip_wsp(&mut self.chars);
self.$parse_func(abs)?;
},
)*
_ => return Err(()),
}
}
}
parse_command!(
b'Z' | b'z' => parse_closepath,
b'L' | b'l' => parse_lineto,
b'H' | b'h' => parse_h_lineto,
b'V' | b'v' => parse_v_lineto,
b'C' | b'c' => parse_curveto,
b'S' | b's' => parse_smooth_curveto,
b'Q' | b'q' => parse_quadratic_bezier_curveto,
b'T' | b't' => parse_smooth_quadratic_bezier_curveto,
b'A' | b'a' => parse_elliprical_arc,
);
},
_ => break, // no more commands.
}
}
Ok(())
}
/// Parse "moveto" command.
fn parse_moveto(&mut self) -> Result<(), ()> {
let command = match self.chars.next() {
Some(c) if c == b'M' || c == b'm' => c,
_ => return Err(()),
};
skip_wsp(&mut self.chars);
let point = parse_coord(&mut self.chars)?;
let absolute = command == b'M';
self.path.push(PathCommand::MoveTo { point, absolute } );
// End of string or the next character is a possible new command.
if !skip_wsp(&mut self.chars) ||
self.chars.peek().map_or(true, |c| c.is_ascii_alphabetic()) {
return Ok(());
}
skip_comma_wsp(&mut self.chars);
// If a moveto is followed by multiple pairs of coordinates, the subsequent
// pairs are treated as implicit lineto commands.
self.parse_lineto(absolute)
}
/// Parse "closepath" command.
fn parse_closepath(&mut self, _absolute: bool) -> Result<(), ()> {
self.path.push(PathCommand::ClosePath);
Ok(())
}
/// Parse "lineto" command.
fn parse_lineto(&mut self, absolute: bool) -> Result<(), ()> {
parse_arguments!(self, absolute, LineTo, [ point => parse_coord ])
}
/// Parse horizontal "lineto" command.
fn parse_h_lineto(&mut self, absolute: bool) -> Result<(), ()> {
parse_arguments!(self, absolute, HorizontalLineTo, [ x => parse_number ])
}
/// Parse vertical "lineto" command.
fn parse_v_lineto(&mut self, absolute: bool) -> Result<(), ()> {
parse_arguments!(self, absolute, VerticalLineTo, [ y => parse_number ])
}
/// Parse cubic Bézier curve command.
fn parse_curveto(&mut self, absolute: bool) -> Result<(), ()> {
parse_arguments!(self, absolute, CurveTo, [
control1 => parse_coord, control2 => parse_coord, point => parse_coord
])
}
/// Parse smooth "curveto" command.
fn parse_smooth_curveto(&mut self, absolute: bool) -> Result<(), ()> {
parse_arguments!(self, absolute, SmoothCurveTo, [
control2 => parse_coord, point => parse_coord
])
}
/// Parse quadratic Bézier curve command.
fn parse_quadratic_bezier_curveto(&mut self, absolute: bool) -> Result<(), ()> {
parse_arguments!(self, absolute, QuadBezierCurveTo, [
control1 => parse_coord, point => parse_coord
])
}
/// Parse smooth quadratic Bézier curveto command.
fn parse_smooth_quadratic_bezier_curveto(&mut self, absolute: bool) -> Result<(), ()> {
parse_arguments!(self, absolute, SmoothQuadBezierCurveTo, [ point => parse_coord ])
}
/// Parse elliptical arc curve command.
fn parse_elliprical_arc(&mut self, absolute: bool) -> Result<(), ()> {
// Parse a flag whose value is '0' or '1'; otherwise, return Err(()).
let parse_flag = |iter: &mut Peekable<Cloned<slice::Iter<u8>>>| -> Result<bool, ()> {
match iter.next() {
Some(c) if c == b'0' || c == b'1' => Ok(c == b'1'),
_ => Err(()),
}
};
parse_arguments!(self, absolute, EllipticalArc, [
rx => parse_number,
ry => parse_number,
angle => parse_number,
large_arc_flag => parse_flag,
sweep_flag => parse_flag,
point => parse_coord
])
}
}
/// Parse a pair of numbers into CoordPair.
fn parse_coord(iter: &mut Peekable<Cloned<slice::Iter<u8>>>) -> Result<CoordPair, ()> {
let x = parse_number(iter)?;
skip_comma_wsp(iter);
let y = parse_number(iter)?;
Ok(CoordPair::new(x, y))
}
/// This is a special version which parses the number for SVG Path. e.g. "M 0.6.5" should be parsed
/// as MoveTo with a coordinate of ("0.6", ".5"), instead of treating 0.6.5 as a non-valid floating
/// point number. In other words, the logic here is similar with that of
/// tokenizer::consume_numeric, which also consumes the number as many as possible, but here the
/// input is a Peekable and we only accept an integer of a floating point number.
///
/// The "number" syntax in https://www.w3.org/TR/SVG/paths.html#PathDataBNF
fn parse_number(iter: &mut Peekable<Cloned<slice::Iter<u8>>>) -> Result<CSSFloat, ()> {
// 1. Check optional sign.
let sign = if iter.peek().map_or(false, |&sign| sign == b'+' || sign == b'-') {
if iter.next().unwrap() == b'-' { -1. } else { 1. }
} else {
1.
};
// 2. Check integer part.
let mut integral_part: f64 = 0.;
let got_dot = if !iter.peek().map_or(false, |&n| n == b'.') {
// If the first digit in integer part is neither a dot nor a digit, this is not a number.
if iter.peek().map_or(true, |n| !n.is_ascii_digit()) {
return Err(());
}
while iter.peek().map_or(false, |n| n.is_ascii_digit()) {
integral_part =
integral_part * 10. + (iter.next().unwrap() - b'0') as f64;
}
iter.peek().map_or(false, |&n| n == b'.')
} else {
true
};
// 3. Check fractional part.
let mut fractional_part: f64 = 0.;
if got_dot {
// Consume '.'.
iter.next();
// If the first digit in fractional part is not a digit, this is not a number.
if iter.peek().map_or(true, |n| !n.is_ascii_digit()) {
return Err(());
}
let mut factor = 0.1;
while iter.peek().map_or(false, |n| n.is_ascii_digit()) {
fractional_part += (iter.next().unwrap() - b'0') as f64 * factor;
factor *= 0.1;
}
}
let mut value = sign * (integral_part + fractional_part);
// 4. Check exp part. The segment name of SVG Path doesn't include 'E' or 'e', so it's ok to
// treat the numbers after 'E' or 'e' are in the exponential part.
if iter.peek().map_or(false, |&exp| exp == b'E' || exp == b'e') {
// Consume 'E' or 'e'.
iter.next();
let exp_sign = if iter.peek().map_or(false, |&sign| sign == b'+' || sign == b'-') {
if iter.next().unwrap() == b'-' { -1. } else { 1. }
} else {
1.
};
let mut exp: f64 = 0.;
while iter.peek().map_or(false, |n| n.is_ascii_digit()) {
exp = exp * 10. + (iter.next().unwrap() - b'0') as f64;
}
value *= f64::powf(10., exp * exp_sign);
}
if value.is_finite() {
Ok(value.min(::std::f32::MAX as f64).max(::std::f32::MIN as f64) as CSSFloat)
} else {
Err(())
}
}
/// Skip all svg whitespaces, and return true if |iter| hasn't finished.
#[inline]
fn skip_wsp(iter: &mut Peekable<Cloned<slice::Iter<u8>>>) -> bool {
// Note: SVG 1.1 defines the whitespaces as \u{9}, \u{20}, \u{A}, \u{D}.
// However, SVG 2 has one extra whitespace: \u{C}.
// Therefore, we follow the newest spec for the definition of whitespace,
// i.e. \u{9}, \u{20}, \u{A}, \u{C}, \u{D}.
while iter.peek().map_or(false, |c| c.is_ascii_whitespace()) {
iter.next();
}
iter.peek().is_some()
}
/// Skip all svg whitespaces and one comma, and return true if |iter| hasn't finished.
#[inline]
fn skip_comma_wsp(iter: &mut Peekable<Cloned<slice::Iter<u8>>>) -> bool {
if !skip_wsp(iter) {
return false;
}
if *iter.peek().unwrap() != b',' {
return true;
}
iter.next();
skip_wsp(iter)
}

View file

@ -19,9 +19,15 @@ where F: for<'t> Fn(&ParserContext, &mut Parser<'static, 't>) -> Result<T, Parse
fn parse_input<'i: 't, 't, T, F>(f: F, input: &'t mut ParserInput<'i>) -> Result<T, ParseError<'i>>
where F: Fn(&ParserContext, &mut Parser<'i, 't>) -> Result<T, ParseError<'i>> {
let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
let context = ParserContext::new(Origin::Author, &url, Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks, None);
let context = ParserContext::new(
Origin::Author,
&url,
Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
let mut parser = Parser::new(input);
f(&context, &mut parser)
}

View file

@ -24,9 +24,15 @@ where
F: Fn(&ParserContext, &mut Parser<'i, 't>) -> Result<T, ParseError<'i>>,
{
let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
let context = ParserContext::new(Origin::Author, &url, Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks, None);
let context = ParserContext::new(
Origin::Author,
&url,
Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
let mut parser = Parser::new(input);
f(&context, &mut parser)
}

View file

@ -301,9 +301,15 @@ fn multiple_stylesheets_cascading() {
#[test]
fn constrain_viewport() {
let url = ServoUrl::parse("http://localhost").unwrap();
let context = ParserContext::new(Origin::Author, &url, Some(CssRuleType::Viewport),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks, None);
let context = ParserContext::new(
Origin::Author,
&url,
Some(CssRuleType::Viewport),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
macro_rules! from_css {
($css:expr) => {