diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 561cc8429de..0adde8d7255 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -54,7 +54,7 @@ use style::logical_geometry::Direction; use style::properties::ComputedValues; use style::selector_parser::{PseudoElement, RestyleDamage}; use style::servo::restyle_damage::ServoRestyleDamage; -use style::values::computed::counters::ContentItem; +use style::values::generics::counters::ContentItem; use style::values::generics::url::UrlOrNone as ImageUrlOrNone; use table::TableFlow; use table_caption::TableCaptionFlow; diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index 35d3e176205..56f92466750 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -66,7 +66,7 @@ use style::values::computed::Gradient; use style::values::computed::effects::SimpleShadow; use style::values::generics::background::BackgroundSize; use style::values::generics::image::{GradientKind, Image, PaintWorklet}; -use style::values::generics::pointing::Cursor; +use style::values::generics::ui::Cursor; use style_traits::CSSPixel; use style_traits::ToCss; use style_traits::cursor::CursorKind; @@ -3012,8 +3012,8 @@ impl ComputedValuesCursorUtility for ComputedValues { #[inline] fn get_cursor(&self, default_cursor: CursorKind) -> Option { match ( - self.get_pointing().pointer_events, - &self.get_pointing().cursor, + self.get_inheritedui().pointer_events, + &self.get_inheritedui().cursor, ) { (PointerEvents::None, _) => None, (PointerEvents::Auto, &Cursor { keyword: CursorKind::Auto, .. }) => Some(default_cursor), diff --git a/components/layout/display_list/conversions.rs b/components/layout/display_list/conversions.rs index e1dff8f1c62..b8c5a8e98b6 100644 --- a/components/layout/display_list/conversions.rs +++ b/components/layout/display_list/conversions.rs @@ -51,6 +51,8 @@ impl ToLayout for Filter { GenericFilter::Sepia(amount) => wr::FilterOp::Sepia(amount.0), // Statically check that DropShadow is impossible. GenericFilter::DropShadow(ref shadow) => match *shadow {}, + // Statically check that Url is impossible. + GenericFilter::Url(ref url) => match *url {}, } } } diff --git a/components/layout/generated_content.rs b/components/layout/generated_content.rs index da390cc9cec..a006fdfa4b4 100644 --- a/components/layout/generated_content.rs +++ b/components/layout/generated_content.rs @@ -20,7 +20,7 @@ use style::computed_values::list_style_type::T as ListStyleType; use style::properties::ComputedValues; use style::selector_parser::RestyleDamage; use style::servo::restyle_damage::ServoRestyleDamage; -use style::values::computed::counters::ContentItem; +use style::values::generics::counters::ContentItem; use text::TextRunScanner; use traversal::InorderFlowTraversal; @@ -240,6 +240,9 @@ impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> { self.traversal.quote -= 1 } } + GeneratedContentInfo::ContentItem(ContentItem::Url(..)) => { + unreachable!("Servo doesn't parse content: url(..) yet") + } } }; diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index c9b9b88bb5d..63507127b07 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -36,7 +36,8 @@ use script_layout_interface::wrapper_traits::{ThreadSafeLayoutElement, ThreadSaf use script_layout_interface::wrapper_traits::GetLayoutData; use style::dom::{NodeInfo, TNode}; use style::selector_parser::RestyleDamage; -use style::values::computed::counters::{Content, ContentItem}; +use style::values::computed::counters::ContentItem; +use style::values::generics::counters::Content; pub trait LayoutNodeLayoutData { /// Similar to borrow_data*, but returns the full PersistentLayoutData rather @@ -113,12 +114,12 @@ impl ThreadSafeLayoutNodeHelpers for T { if self.get_pseudo_element_type().is_replaced_content() { let style = self.as_element().unwrap().resolved_style(); - return match style.as_ref().get_counters().content { - Content::Items(ref value) if !value.is_empty() => { - TextContent::GeneratedContent((*value).to_vec()) + return TextContent::GeneratedContent( + match style.as_ref().get_counters().content { + Content::Items(ref value) => value.to_vec(), + _ => vec![], } - _ => TextContent::GeneratedContent(vec![]), - }; + ); } TextContent::Text(self.node_text_content().into_boxed_str()) diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 78d09bac3ea..951360b8f5e 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -145,11 +145,11 @@ impl nsStyleImage { match image { GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient), GenericImage::Url(ref url) => unsafe { - bindings::Gecko_SetLayerImageImageValue(self, url.image_value.get()); + bindings::Gecko_SetLayerImageImageValue(self, url.0.image_value.get()); }, GenericImage::Rect(ref image_rect) => { unsafe { - bindings::Gecko_SetLayerImageImageValue(self, image_rect.url.image_value.get()); + bindings::Gecko_SetLayerImageImageValue(self, image_rect.url.0.image_value.get()); bindings::Gecko_InitializeImageCropRect(self); // Set CropRect diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index 7d9724cc6c5..554606bb9db 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -7,7 +7,7 @@ use app_units::AU_PER_PX; use app_units::Au; use context::QuirksMode; -use cssparser::{BasicParseErrorKind, Parser, Token, RGBA}; +use cssparser::{BasicParseErrorKind, Parser, RGBA}; use euclid::Size2D; use euclid::TypedScale; use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor}; @@ -32,7 +32,7 @@ use stylesheets::Origin; use values::{serialize_atom_identifier, CSSFloat, CustomIdent, KeyframesName}; use values::computed::{self, ToComputedValue}; use values::computed::font::FontSize; -use values::specified::{Integer, Length, Number}; +use values::specified::{Integer, Length, Number, Resolution}; /// The `Device` in Gecko wraps a pres context, has a default values computed, /// and contains all the viewport rule state. @@ -286,53 +286,6 @@ impl PartialEq for Expression { } } -/// A resolution. -#[derive(Clone, Debug, PartialEq, ToCss)] -pub enum Resolution { - /// Dots per inch. - #[css(dimension)] - Dpi(CSSFloat), - /// Dots per pixel. - #[css(dimension)] - Dppx(CSSFloat), - /// Dots per centimeter. - #[css(dimension)] - Dpcm(CSSFloat), -} - -impl Resolution { - fn to_dpi(&self) -> CSSFloat { - match *self { - Resolution::Dpi(f) => f, - Resolution::Dppx(f) => f * 96.0, - Resolution::Dpcm(f) => f * 2.54, - } - } - - fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { - let location = input.current_source_location(); - let (value, unit) = match *input.next()? { - Token::Dimension { - value, ref unit, .. - } => (value, unit), - ref t => return Err(location.new_unexpected_token_error(t.clone())), - }; - - if value <= 0. { - return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); - } - - (match_ignore_ascii_case! { &unit, - "dpi" => Ok(Resolution::Dpi(value)), - "dppx" => Ok(Resolution::Dppx(value)), - "dpcm" => Ok(Resolution::Dpcm(value)), - _ => Err(()) - }).map_err(|()| { - location.new_custom_error(StyleParseErrorKind::UnexpectedDimension(unit.clone())) - }) - } -} - /// A value found or expected in a media expression. /// /// FIXME(emilio): How should calc() serialize in the Number / Integer / @@ -535,7 +488,7 @@ fn parse_feature_value<'i, 't>( MediaExpressionValue::IntRatio(a.value() as u32, b.value() as u32) }, nsMediaFeature_ValueType::eResolution => { - MediaExpressionValue::Resolution(Resolution::parse(input)?) + MediaExpressionValue::Resolution(Resolution::parse(context, input)?) }, nsMediaFeature_ValueType::eEnumerated => { let location = input.current_source_location(); diff --git a/components/style/gecko/pseudo_element_definition.mako.rs b/components/style/gecko/pseudo_element_definition.mako.rs index 275a04e5bc4..caaeeac629d 100644 --- a/components/style/gecko/pseudo_element_definition.mako.rs +++ b/components/style/gecko/pseudo_element_definition.mako.rs @@ -216,11 +216,7 @@ impl PseudoElement { None } - /// Constructs an atom from a string of text, and whether we're in a - /// user-agent stylesheet. - /// - /// If we're not in a user-agent stylesheet, we will never parse anonymous - /// box pseudo-elements. + /// Constructs a pseudo-element from a string of text. /// /// Returns `None` if the pseudo-element is not recognised. #[inline] @@ -234,6 +230,10 @@ impl PseudoElement { return Some(${pseudo_element_variant(pseudo)}) } % endfor + // Alias "-moz-selection" to "selection" at parse time. + "-moz-selection" => { + return Some(PseudoElement::Selection); + } _ => { // FIXME: -moz-tree check should probably be // ascii-case-insensitive. diff --git a/components/style/gecko/url.rs b/components/style/gecko/url.rs index bca7e10883a..d371f0a74e5 100644 --- a/components/style/gecko/url.rs +++ b/components/style/gecko/url.rs @@ -12,10 +12,13 @@ use gecko_bindings::structs::root::{RustString, nsStyleImageRequest}; use gecko_bindings::structs::root::mozilla::css::{ImageValue, URLValue}; use gecko_bindings::sugar::refptr::RefPtr; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; +use nsstring::nsCString; use parser::{Parse, ParserContext}; use servo_arc::{Arc, RawOffsetArc}; +use std::fmt::{self, Write}; use std::mem; -use style_traits::ParseError; +use style_traits::{CssWriter, ParseError, ToCss}; +use values::computed::{Context, ToComputedValue}; /// A CSS url() value for gecko. #[css(function = "url")] @@ -70,10 +73,8 @@ impl CssUrl { self.as_str().chars().next().map_or(false, |c| c == '#') } - /// Return the resolved url as string, or the empty string if it's invalid. - /// - /// FIXME(bholley): This returns the unresolved URL while the servo version - /// returns the resolved URL. + /// Return the unresolved url as string, or the empty string if it's + /// invalid. pub fn as_str(&self) -> &str { &*self.serialization } @@ -121,7 +122,7 @@ impl MallocSizeOf for CssUrl { } /// A specified url() value for general usage. -#[derive(Clone, Debug, SpecifiedValueInfo, ToComputedValue, ToCss)] +#[derive(Clone, Debug, SpecifiedValueInfo, ToCss)] pub struct SpecifiedUrl { /// The specified url value. pub url: CssUrl, @@ -139,15 +140,11 @@ impl SpecifiedUrl { debug_assert!(!ptr.is_null()); RefPtr::from_addrefed(ptr) }; - SpecifiedUrl { url, url_value } - } - - /// Convert from URLValueData to SpecifiedUrl. - pub unsafe fn from_url_value_data(url: &URLValueData) -> Result { - CssUrl::from_url_value_data(url).map(Self::from_css_url) + Self { url, url_value } } } + impl PartialEq for SpecifiedUrl { fn eq(&self, other: &Self) -> bool { self.url.eq(&other.url) @@ -179,7 +176,7 @@ impl MallocSizeOf for SpecifiedUrl { /// A specified url() value for image. /// /// This exists so that we can construct `ImageValue` and reuse it. -#[derive(Clone, Debug, SpecifiedValueInfo, ToComputedValue, ToCss)] +#[derive(Clone, Debug, SpecifiedValueInfo, ToCss)] pub struct SpecifiedImageUrl { /// The specified url value. pub url: CssUrl, @@ -190,16 +187,6 @@ pub struct SpecifiedImageUrl { } impl SpecifiedImageUrl { - fn from_css_url(url: CssUrl) -> Self { - let image_value = unsafe { - let ptr = bindings::Gecko_ImageValue_Create(url.for_ffi()); - // We do not expect Gecko_ImageValue_Create returns null. - debug_assert!(!ptr.is_null()); - RefPtr::from_addrefed(ptr) - }; - SpecifiedImageUrl { url, image_value } - } - /// Parse a URL from a string value. See SpecifiedUrl::parse_from_string. pub fn parse_from_string<'a>( url: String, @@ -208,20 +195,14 @@ impl SpecifiedImageUrl { CssUrl::parse_from_string(url, context).map(Self::from_css_url) } - /// Convert from URLValueData to SpecifiedUrl. - pub unsafe fn from_url_value_data(url: &URLValueData) -> Result { - CssUrl::from_url_value_data(url).map(Self::from_css_url) - } - - /// Convert from nsStyleImageRequest to SpecifiedUrl. - pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Result { - if image_request.mImageValue.mRawPtr.is_null() { - return Err(()); - } - - let image_value = image_request.mImageValue.mRawPtr.as_ref().unwrap(); - let url_value_data = &image_value._base; - Self::from_url_value_data(url_value_data) + fn from_css_url(url: CssUrl) -> Self { + let image_value = unsafe { + let ptr = bindings::Gecko_ImageValue_Create(url.for_ffi()); + // We do not expect Gecko_ImageValue_Create returns null. + debug_assert!(!ptr.is_null()); + RefPtr::from_addrefed(ptr) + }; + Self { url, image_value } } } @@ -253,7 +234,104 @@ impl MallocSizeOf for SpecifiedImageUrl { } } +impl ToComputedValue for SpecifiedUrl { + type ComputedValue = ComputedUrl; + + #[inline] + fn to_computed_value(&self, _: &Context) -> Self::ComputedValue { + ComputedUrl(self.clone()) + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + computed.0.clone() + } +} + +impl ToComputedValue for SpecifiedImageUrl { + type ComputedValue = ComputedImageUrl; + + #[inline] + fn to_computed_value(&self, _: &Context) -> Self::ComputedValue { + ComputedImageUrl(self.clone()) + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + computed.0.clone() + } +} + +fn serialize_computed_url( + url_value_data: &URLValueData, + dest: &mut CssWriter, +) -> fmt::Result +where + W: Write, +{ + dest.write_str("url(")?; + unsafe { + let mut string = nsCString::new(); + bindings::Gecko_GetComputedURLSpec(url_value_data, &mut string); + string.as_str_unchecked().to_css(dest)?; + } + dest.write_char(')') +} + /// The computed value of a CSS `url()`. -pub type ComputedUrl = SpecifiedUrl; +/// +/// The only difference between specified and computed URLs is the +/// serialization. +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] +pub struct ComputedUrl(pub SpecifiedUrl); + +impl ToCss for ComputedUrl { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write + { + serialize_computed_url(&self.0.url_value._base, dest) + } +} + +impl ComputedUrl { + /// Convert from URLValueData to ComputedUrl. + pub unsafe fn from_url_value_data(url: &URLValueData) -> Result { + Ok(ComputedUrl( + SpecifiedUrl::from_css_url(CssUrl::from_url_value_data(url)?) + )) + } +} + /// The computed value of a CSS `url()` for image. -pub type ComputedImageUrl = SpecifiedImageUrl; +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] +pub struct ComputedImageUrl(pub SpecifiedImageUrl); + +impl ToCss for ComputedImageUrl { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write + { + serialize_computed_url(&self.0.image_value._base, dest) + } +} + +impl ComputedImageUrl { + /// Convert from URLValueData to SpecifiedUrl. + pub unsafe fn from_url_value_data(url: &URLValueData) -> Result { + Ok(ComputedImageUrl( + SpecifiedImageUrl::from_css_url(CssUrl::from_url_value_data(url)?) + )) + } + + /// Convert from nsStyleImageReques to ComputedImageUrl. + pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Result { + if image_request.mImageValue.mRawPtr.is_null() { + return Err(()); + } + + let image_value = image_request.mImageValue.mRawPtr.as_ref().unwrap(); + let url_value_data = &image_value._base; + Self::from_url_value_data(url_value_data) + } +} diff --git a/components/style/gecko_bindings/sugar/style_complex_color.rs b/components/style/gecko_bindings/sugar/style_complex_color.rs index 0d5a20944a8..0e06b4c50ba 100644 --- a/components/style/gecko_bindings/sugar/style_complex_color.rs +++ b/components/style/gecko_bindings/sugar/style_complex_color.rs @@ -7,7 +7,7 @@ use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor}; use gecko_bindings::structs::{nscolor, StyleComplexColor}; use values::computed::Color as ComputedColor; -use values::generics::pointing::CaretColor; +use values::generics::ui::CaretColor; impl From for StyleComplexColor { fn from(other: nscolor) -> Self { diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 3ca9d347157..df1c8d2890a 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -4,7 +4,7 @@ import re -PHYSICAL_SIDES = ["top", "left", "bottom", "right"] +PHYSICAL_SIDES = ["top", "right", "bottom", "left"] LOGICAL_SIDES = ["block-start", "block-end", "inline-start", "inline-end"] PHYSICAL_SIZES = ["width", "height"] LOGICAL_SIZES = ["block-size", "inline-size"] diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 4479d040564..3f20b8328bd 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -10,6 +10,7 @@ %> <%namespace name="helpers" file="/helpers.mako.rs" /> +use Atom; use app_units::Au; use custom_properties::CustomPropertiesMap; use gecko_bindings::bindings; @@ -60,7 +61,7 @@ use std::mem::{forget, uninitialized, transmute, zeroed}; use std::{cmp, ops, ptr}; use values::{self, CustomIdent, Either, KeyframesName, None_}; use values::computed::{NonNegativeLength, ToComputedValue, Percentage}; -use values::computed::font::{FontSize, SingleFontFamily}; +use values::computed::font::FontSize; use values::computed::effects::{BoxShadow, Filter, SimpleShadow}; use values::computed::outline::OutlineStyle; use values::generics::column::ColumnCount; @@ -126,8 +127,6 @@ impl ComputedValues { } pub fn pseudo(&self) -> Option { - use string_cache::Atom; - let atom = (self.0).mPseudoTag.mRawPtr; if atom.is_null() { return None; @@ -698,7 +697,7 @@ def set_gecko_property(ffi_name, expr): } SVGPaintKind::PaintServer(url) => { unsafe { - bindings::Gecko_nsStyleSVGPaint_SetURLValue(paint, url.url_value.get()); + bindings::Gecko_nsStyleSVGPaint_SetURLValue(paint, url.0.url_value.get()); } } SVGPaintKind::Color(color) => { @@ -738,8 +737,8 @@ def set_gecko_property(ffi_name, expr): #[allow(non_snake_case)] pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { + use values::computed::url::ComputedUrl; use values::generics::svg::{SVGPaint, SVGPaintKind}; - use values::specified::url::SpecifiedUrl; use self::structs::nsStyleSVGPaintType; use self::structs::nsStyleSVGFallbackType; let ref paint = ${get_gecko_property(gecko_ffi_name)}; @@ -761,7 +760,7 @@ def set_gecko_property(ffi_name, expr): nsStyleSVGPaintType::eStyleSVGPaintType_Server => { unsafe { SVGPaintKind::PaintServer( - SpecifiedUrl::from_url_value_data( + ComputedUrl::from_url_value_data( &(**paint.mPaint.mPaintServer.as_ref())._base ).unwrap() ) @@ -940,7 +939,7 @@ def set_gecko_property(ffi_name, expr): pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { match v { UrlOrNone::Url(ref url) => { - self.gecko.${gecko_ffi_name}.set_move(url.url_value.clone()) + self.gecko.${gecko_ffi_name}.set_move(url.0.url_value.clone()) } UrlOrNone::None => { unsafe { @@ -962,16 +961,18 @@ def set_gecko_property(ffi_name, expr): #[allow(non_snake_case)] pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - use values::specified::url::SpecifiedUrl; + use values::computed::url::ComputedUrl; if self.gecko.${gecko_ffi_name}.mRawPtr.is_null() { - UrlOrNone::none() - } else { - unsafe { - let ref gecko_url_value = *self.gecko.${gecko_ffi_name}.mRawPtr; - UrlOrNone::Url(SpecifiedUrl::from_url_value_data(&gecko_url_value._base) - .expect("${gecko_ffi_name} could not convert to SpecifiedUrl")) - } + return UrlOrNone::none() + } + + unsafe { + let gecko_url_value = &*self.gecko.${gecko_ffi_name}.mRawPtr; + UrlOrNone::Url( + ComputedUrl::from_url_value_data(&gecko_url_value._base) + .expect("${gecko_ffi_name} could not convert to ComputedUrl") + ) } } @@ -1861,7 +1862,6 @@ fn static_assert() { pub fn clone_${value.name}(&self) -> longhands::${value.name}::computed_value::T { use gecko_bindings::structs::{nsStyleGridLine_kMinLine, nsStyleGridLine_kMaxLine}; - use string_cache::Atom; longhands::${value.name}::computed_value::T { is_span: self.gecko.${value.gecko}.mHasSpan, @@ -2034,7 +2034,6 @@ fn static_assert() { pub fn clone_grid_template_${kind}(&self) -> longhands::grid_template_${kind}::computed_value::T { <% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %> - use Atom; use gecko_bindings::structs::nsTArray; use nsstring::nsStringRepr; use values::CustomIdent; @@ -2309,14 +2308,6 @@ fn static_assert() { self.gecko.mFont.fontlist.mFontlist.mBasePtr.set_move((v.0).0.clone()); } - pub fn font_family_count(&self) -> usize { - 0 - } - - pub fn font_family_at(&self, _: usize) -> SingleFontFamily { - unimplemented!() - } - pub fn copy_font_family_from(&mut self, other: &Self) { unsafe { Gecko_CopyFontFamilyFrom(&mut self.gecko.mFont, &other.gecko.mFont); } self.gecko.mGenericID = other.gecko.mGenericID; @@ -2335,14 +2326,25 @@ fn static_assert() { let shared_fontlist = unsafe { fontlist.mFontlist.mBasePtr.to_safe() }; if shared_fontlist.mNames.is_empty() { - let default = match fontlist.mDefaultFontType { + let default = fontlist.mDefaultFontType; + let default = match default { FontFamilyType::eFamily_serif => { SingleFontFamily::Generic(atom!("serif")) } - FontFamilyType::eFamily_sans_serif => { + _ => { + // This can break with some combinations of user prefs, see + // bug 1442195 for example. It doesn't really matter in this + // case... + // + // FIXME(emilio): Probably should be storing the whole + // default font name instead though. + debug_assert_eq!( + default, + FontFamilyType::eFamily_sans_serif, + "Default generic should be serif or sans-serif" + ); SingleFontFamily::Generic(atom!("sans-serif")) } - _ => panic!("Default generic must be serif or sans-serif"), }; FontFamily(FontFamilyList::new(Box::new([default]))) } else { @@ -2683,6 +2685,18 @@ fn static_assert() { } } + #[allow(non_snake_case)] + pub fn reset__x_lang(&mut self, other: &Self) { + self.copy__x_lang_from(other) + } + + #[allow(non_snake_case)] + pub fn clone__x_lang(&self) -> longhands::_x_lang::computed_value::T { + longhands::_x_lang::computed_value::T(unsafe { + Atom::from_raw(self.gecko.mLanguage.mRawPtr) + }) + } + #[allow(non_snake_case)] pub fn set__x_text_zoom(&mut self, v: longhands::_x_text_zoom::computed_value::T) { self.gecko.mAllowZoom = v.0; @@ -2699,8 +2713,8 @@ fn static_assert() { } #[allow(non_snake_case)] - pub fn reset__x_lang(&mut self, other: &Self) { - self.copy__x_lang_from(other) + pub fn clone__x_text_zoom(&self) -> longhands::_x_text_zoom::computed_value::T { + longhands::_x_text_zoom::computed_value::T(self.gecko.mAllowZoom) } ${impl_simple("_moz_script_level", "mScriptLevel")} @@ -2777,7 +2791,6 @@ fn static_assert() { } pub fn clone_font_variant_alternates(&self) -> values::computed::font::FontVariantAlternates { - use Atom; % for value in "normal swash stylistic ornaments annotation styleset character_variant historical".split(): use gecko_bindings::structs::NS_FONT_VARIANT_ALTERNATES_${value.upper()}; % endfor @@ -2833,6 +2846,13 @@ fn static_assert() { ${impl_simple_type_with_conversion("font_variant_east_asian", "mFont.variantEastAsian")} ${impl_simple_type_with_conversion("font_variant_numeric", "mFont.variantNumeric")} + #[allow(non_snake_case)] + pub fn clone__moz_min_font_size_ratio( + &self, + ) -> longhands::_moz_min_font_size_ratio::computed_value::T { + Percentage(self.gecko.mMinFontSizeRatio as f32 / 100.) + } + #[allow(non_snake_case)] pub fn set__moz_min_font_size_ratio(&mut self, v: longhands::_moz_min_font_size_ratio::computed_value::T) { let scaled = v.0 * 100.; @@ -3286,7 +3306,6 @@ fn static_assert() { use gecko_bindings::structs::nsCSSPropertyID::eCSSPropertyExtra_no_properties; use gecko_bindings::structs::nsCSSPropertyID::eCSSPropertyExtra_variable; use gecko_bindings::structs::nsCSSPropertyID::eCSSProperty_UNKNOWN; - use Atom; let property = self.gecko.mTransitions[index].mProperty; if property == eCSSProperty_UNKNOWN || property == eCSSPropertyExtra_variable { @@ -3384,7 +3403,6 @@ fn static_assert() { pub fn animation_name_at(&self, index: usize) -> longhands::animation_name::computed_value::SingleComputedValue { use properties::longhands::animation_name::single_value::SpecifiedValue as AnimationName; - use Atom; let atom = self.gecko.mAnimations[index].mName.mRawPtr; if atom == atom!("").as_ptr() { @@ -3590,7 +3608,6 @@ fn static_assert() { use properties::longhands::will_change::computed_value::T; use gecko_bindings::structs::nsAtom; use values::CustomIdent; - use Atom; if self.gecko.mWillChange.len() == 0 { return T::Auto @@ -4106,12 +4123,8 @@ fn static_assert() { } UrlOrNone::Url(ref url) => { unsafe { - Gecko_SetListStyleImageImageValue(&mut self.gecko, url.image_value.get()); + Gecko_SetListStyleImageImageValue(&mut self.gecko, url.0.image_value.get()); } - // We don't need to record this struct as uncacheable, like when setting - // background-image to a url() value, since only properties in reset structs - // are re-used from the applicable declaration cache, and the List struct - // is an inherited struct. } } } @@ -4125,7 +4138,7 @@ fn static_assert() { } pub fn clone_list_style_image(&self) -> longhands::list_style_image::computed_value::T { - use values::specified::url::SpecifiedImageUrl; + use values::computed::url::ComputedImageUrl; if self.gecko.mListStyleImage.mRawPtr.is_null() { return UrlOrNone::None; @@ -4133,8 +4146,9 @@ fn static_assert() { unsafe { let ref gecko_image_request = *self.gecko.mListStyleImage.mRawPtr; - UrlOrNone::Url(SpecifiedImageUrl::from_image_request(gecko_image_request) - .expect("mListStyleImage could not convert to SpecifiedImageUrl")) + UrlOrNone::Url(ComputedImageUrl::from_image_request( + gecko_image_request + ).expect("mListStyleImage could not convert to ComputedImageUrl")) } } @@ -4269,6 +4283,13 @@ fn static_assert() { self.gecko.mSpan = v.0 } + #[allow(non_snake_case)] + pub fn clone__x_span(&self) -> longhands::_x_span::computed_value::T { + longhands::_x_span::computed_value::T( + self.gecko.mSpan + ) + } + ${impl_simple_copy('_x_span', 'mSpan')} @@ -4473,7 +4494,7 @@ fn static_assert() { }, Url(ref url) => { unsafe { - bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, url.url_value.get()); + bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, url.0.url_value.get()); } }, } @@ -4492,7 +4513,7 @@ fn static_assert() { pub fn clone_filter(&self) -> longhands::filter::computed_value::T { use values::generics::effects::Filter; - use values::specified::url::SpecifiedUrl; + use values::computed::url::ComputedUrl; use gecko_bindings::structs::NS_STYLE_FILTER_BLUR; use gecko_bindings::structs::NS_STYLE_FILTER_BRIGHTNESS; use gecko_bindings::structs::NS_STYLE_FILTER_CONTRAST; @@ -4534,7 +4555,7 @@ fn static_assert() { NS_STYLE_FILTER_URL => { filters.push(unsafe { Filter::Url( - SpecifiedUrl::from_url_value_data(&(**filter.__bindgen_anon_1.mURL.as_ref())._base).unwrap() + ComputedUrl::from_url_value_data(&(**filter.__bindgen_anon_1.mURL.as_ref())._base).unwrap() ) }); } @@ -5000,7 +5021,7 @@ fn static_assert() { % if ident == "clip_path": ShapeSource::ImageOrUrl(ref url) => { unsafe { - bindings::Gecko_StyleShapeSource_SetURLValue(${ident}, url.url_value.get()) + bindings::Gecko_StyleShapeSource_SetURLValue(${ident}, url.0.url_value.get()) } } % elif ident == "shape_outside": @@ -5213,10 +5234,28 @@ clip-path SVGStrokeDashArray::Values(vec) } + #[allow(non_snake_case)] + pub fn _moz_context_properties_count(&self) -> usize { + self.gecko.mContextProps.len() + } + + #[allow(non_snake_case)] + pub fn _moz_context_properties_at( + &self, + index: usize, + ) -> longhands::_moz_context_properties::computed_value::single_value::T { + longhands::_moz_context_properties::computed_value::single_value::T( + CustomIdent(unsafe { + Atom::from_raw(self.gecko.mContextProps[index].mRawPtr) + }) + ) + } + #[allow(non_snake_case)] pub fn set__moz_context_properties(&mut self, v: I) - where I: IntoIterator, - I::IntoIter: ExactSizeIterator + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator { let v = v.into_iter(); unsafe { @@ -5266,7 +5305,7 @@ clip-path } -<%self:impl_trait style_struct_name="Pointing" +<%self:impl_trait style_struct_name="InheritedUI" skip_longhands="cursor caret-color"> pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) { use style_traits::cursor::CursorKind; @@ -5322,15 +5361,10 @@ clip-path unsafe { Gecko_SetCursorImageValue( &mut self.gecko.mCursorImages[i], - v.images[i].url.image_value.get(), + v.images[i].url.0.image_value.get(), ); } - // We don't need to record this struct as uncacheable, like when setting - // background-image to a url() value, since only properties in reset structs - // are re-used from the applicable declaration cache, and the Pointing struct - // is an inherited struct. - match v.images[i].hotspot { Some((x, y)) => { self.gecko.mCursorImages[i].mHaveHotspot = true; @@ -5356,9 +5390,9 @@ clip-path } pub fn clone_cursor(&self) -> longhands::cursor::computed_value::T { - use values::computed::pointing::CursorImage; + use values::computed::ui::CursorImage; + use values::computed::url::ComputedImageUrl; use style_traits::cursor::CursorKind; - use values::specified::url::SpecifiedImageUrl; let keyword = match self.gecko.mCursor as u32 { structs::NS_STYLE_CURSOR_AUTO => CursorKind::Auto, @@ -5403,8 +5437,8 @@ clip-path let images = self.gecko.mCursorImages.iter().map(|gecko_cursor_image| { let url = unsafe { let gecko_image_request = gecko_cursor_image.mImage.mRawPtr.as_ref().unwrap(); - SpecifiedImageUrl::from_image_request(&gecko_image_request) - .expect("mCursorImages.mImage could not convert to SpecifiedImageUrl") + ComputedImageUrl::from_image_request(&gecko_image_request) + .expect("mCursorImages.mImage could not convert to ComputedImageUrl") }; let hotspot = @@ -5463,7 +5497,7 @@ clip-path pub fn set_content(&mut self, v: longhands::content::computed_value::T, device: &Device) { use values::CustomIdent; - use values::computed::counters::{Content, ContentItem}; + use values::generics::counters::{Content, ContentItem}; use values::generics::CounterStyleOrNone; use gecko_bindings::structs::nsStyleContentData; use gecko_bindings::structs::nsStyleContentAttr; @@ -5590,7 +5624,7 @@ clip-path unsafe { bindings::Gecko_SetContentDataImageValue( &mut self.gecko.mContents[i], - url.image_value.get(), + url.0.image_value.get(), ) } } @@ -5615,10 +5649,10 @@ clip-path use {Atom, Namespace}; use gecko::conversions::string_from_chars_pointer; use gecko_bindings::structs::nsStyleContentType::*; - use values::computed::counters::{Content, ContentItem}; + use values::generics::counters::{Content, ContentItem}; + use values::computed::url::ComputedImageUrl; use values::{CustomIdent, Either}; use values::generics::CounterStyleOrNone; - use values::specified::url::SpecifiedImageUrl; use values::specified::Attr; if self.gecko.mContents.is_empty() { @@ -5679,8 +5713,8 @@ clip-path let gecko_image_request = &**gecko_content.mContent.mImage.as_ref(); ContentItem::Url( - SpecifiedImageUrl::from_image_request(gecko_image_request) - .expect("mContent could not convert to SpecifiedImageUrl") + ComputedImageUrl::from_image_request(gecko_image_request) + .expect("mContent could not convert to ComputedImageUrl") ) } }, @@ -5719,7 +5753,6 @@ clip-path ) -> longhands::counter_${counter_property.lower()}::computed_value::T { use values::generics::counters::CounterPair; use values::CustomIdent; - use gecko_string_cache::Atom; longhands::counter_${counter_property.lower()}::computed_value::T::new( self.gecko.m${counter_property}s.iter().map(|ref gecko_counter| { diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 017996f87b5..ff6670c3274 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -759,7 +759,7 @@ <%def name="four_sides_shorthand(name, sub_property_pattern, parser_function, needs_context=True, allow_quirks=False, **kwargs)"> - <% sub_properties=' '.join(sub_property_pattern % side for side in ['top', 'right', 'bottom', 'left']) %> + <% sub_properties=' '.join(sub_property_pattern % side for side in PHYSICAL_SIDES) %> <%call expr="self.shorthand(name, sub_properties=sub_properties, **kwargs)"> #[allow(unused_imports)] use parser::Parse; diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs index d6b9e6e69ba..a1f1b039434 100644 --- a/components/style/properties/longhand/background.mako.rs +++ b/components/style/properties/longhand/background.mako.rs @@ -54,7 +54,7 @@ ${helpers.predefined_type( ${helpers.single_keyword("background-attachment", "scroll fixed" + (" local" if product == "gecko" else ""), vector=True, - gecko_constant_prefix="NS_STYLE_IMAGELAYER_ATTACHMENT", + 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")} diff --git a/components/style/properties/longhand/inherited_svg.mako.rs b/components/style/properties/longhand/inherited_svg.mako.rs index 063a4418181..b3bc12b1367 100644 --- a/components/style/properties/longhand/inherited_svg.mako.rs +++ b/components/style/properties/longhand/inherited_svg.mako.rs @@ -136,6 +136,7 @@ ${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)", diff --git a/components/style/properties/longhand/pointing.mako.rs b/components/style/properties/longhand/inherited_ui.mako.rs similarity index 95% rename from components/style/properties/longhand/pointing.mako.rs rename to components/style/properties/longhand/inherited_ui.mako.rs index 6dbb71c59ae..3b516e2f1ce 100644 --- a/components/style/properties/longhand/pointing.mako.rs +++ b/components/style/properties/longhand/inherited_ui.mako.rs @@ -4,7 +4,7 @@ <%namespace name="helpers" file="/helpers.mako.rs" /> -<% data.new_style_struct("Pointing", inherited=True, gecko_name="UserInterface") %> +<% data.new_style_struct("InheritedUI", inherited=True, gecko_name="UserInterface") %> ${helpers.predefined_type("cursor", "Cursor", @@ -44,7 +44,7 @@ ${helpers.single_keyword("-moz-user-focus", ${helpers.predefined_type( "caret-color", "CaretColor", - "generics::pointing::CaretColor::Auto", + "generics::ui::CaretColor::Auto", spec="https://drafts.csswg.org/css-ui/#caret-color", animation_value_type="AnimatedCaretColor", ignored_when_colors_disabled=True, diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 5e3d8eaeaaf..9e5d4c3b7f1 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -109,11 +109,11 @@ pub mod longhands { <%include file="/longhand/inherited_box.mako.rs" /> <%include file="/longhand/inherited_table.mako.rs" /> <%include file="/longhand/inherited_text.mako.rs" /> + <%include file="/longhand/inherited_ui.mako.rs" /> <%include file="/longhand/list.mako.rs" /> <%include file="/longhand/margin.mako.rs" /> <%include file="/longhand/outline.mako.rs" /> <%include file="/longhand/padding.mako.rs" /> - <%include file="/longhand/pointing.mako.rs" /> <%include file="/longhand/position.mako.rs" /> <%include file="/longhand/table.mako.rs" /> <%include file="/longhand/text.mako.rs" /> @@ -2399,6 +2399,18 @@ pub mod style_structs { -> longhands::${longhand.ident}::computed_value::SingleComputedValue { self.${longhand.ident}_at(index % self.${longhand.ident}_count()) } + + /// Clone the computed value for the property. + #[allow(non_snake_case)] + #[inline] + #[cfg(feature = "gecko")] + pub fn clone_${longhand.ident}( + &self, + ) -> longhands::${longhand.ident}::computed_value::T { + longhands::${longhand.ident}::computed_value::T( + self.${longhand.ident}_iter().collect() + ) + } % endif % endfor @@ -2631,10 +2643,10 @@ impl ComputedValuesInner { /// ineffective, and would yield an empty `::before` or `::after` /// pseudo-element. pub fn ineffective_content_property(&self) -> bool { - use properties::longhands::content::computed_value::T; + use values::generics::counters::Content; match self.get_counters().content { - T::Normal | T::None => true, - T::Items(ref items) => items.is_empty(), + Content::Normal | Content::None => true, + Content::Items(ref items) => items.is_empty(), } } diff --git a/components/style/values/animated/effects.rs b/components/style/values/animated/effects.rs index 9ce9c3be9a7..e0f4cf7b7c0 100644 --- a/components/style/values/animated/effects.rs +++ b/components/style/values/animated/effects.rs @@ -14,6 +14,8 @@ use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; use values::animated::color::RGBA; use values::computed::{Angle, Number}; use values::computed::length::Length; +#[cfg(feature = "gecko")] +use values::computed::url::ComputedUrl; use values::distance::{ComputeSquaredDistance, SquaredDistance}; use values::generics::effects::BoxShadow as GenericBoxShadow; use values::generics::effects::Filter as GenericFilter; @@ -42,11 +44,11 @@ pub struct FilterList(pub Vec); /// An animated value for a single `filter`. #[cfg(feature = "gecko")] -pub type Filter = GenericFilter; +pub type Filter = GenericFilter; /// An animated value for a single `filter`. #[cfg(not(feature = "gecko"))] -pub type Filter = GenericFilter; +pub type Filter = GenericFilter; /// An animated value for the `drop-shadow()` filter. pub type SimpleShadow = GenericSimpleShadow, Length, Length>; diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs index ec31f7ab18c..533d917be6f 100644 --- a/components/style/values/animated/mod.rs +++ b/components/style/values/animated/mod.rs @@ -15,9 +15,7 @@ use values::computed::Angle as ComputedAngle; use values::computed::BorderCornerRadius as ComputedBorderCornerRadius; use values::computed::MaxLength as ComputedMaxLength; use values::computed::MozLength as ComputedMozLength; -#[cfg(feature = "servo")] use values::computed::url::ComputedUrl; -use values::specified::url::SpecifiedUrl; pub mod color; pub mod effects; @@ -260,8 +258,6 @@ macro_rules! trivial_to_animated_value { trivial_to_animated_value!(Au); trivial_to_animated_value!(ComputedAngle); -trivial_to_animated_value!(SpecifiedUrl); -#[cfg(feature = "servo")] trivial_to_animated_value!(ComputedUrl); trivial_to_animated_value!(bool); trivial_to_animated_value!(f32); diff --git a/components/style/values/computed/counters.rs b/components/style/values/computed/counters.rs index 3cae67f22f7..fd8d7763f1c 100644 --- a/components/style/values/computed/counters.rs +++ b/components/style/values/computed/counters.rs @@ -4,22 +4,10 @@ //! Computed values for counter properties -#[cfg(feature = "servo")] -use computed_values::list_style_type::T as ListStyleType; -use cssparser::{Parser, Token}; -use parser::{Parse, ParserContext}; -use selectors::parser::SelectorParseErrorKind; -use style_traits::{ParseError, StyleParseErrorKind}; -use values::CustomIdent; -#[cfg(feature = "gecko")] -use values::generics::CounterStyleOrNone; +use values::computed::url::ComputedImageUrl; +use values::generics::counters as generics; use values::generics::counters::CounterIncrement as GenericCounterIncrement; use values::generics::counters::CounterReset as GenericCounterReset; -#[cfg(feature = "gecko")] -use values::specified::Attr; -#[cfg(feature = "gecko")] -use values::specified::url::SpecifiedImageUrl; -pub use values::specified::{Content, ContentItem}; /// A computed value for the `counter-increment` property. pub type CounterIncrement = GenericCounterIncrement; @@ -27,134 +15,9 @@ pub type CounterIncrement = GenericCounterIncrement; /// A computed value for the `counter-increment` property. pub type CounterReset = GenericCounterReset; -impl Content { - /// Set `content` property to `normal`. - #[inline] - pub fn normal() -> Self { - Content::Normal - } +/// A computed value for the `content` property. +pub type Content = generics::Content; - #[cfg(feature = "servo")] - fn parse_counter_style(input: &mut Parser) -> ListStyleType { - input - .try(|input| { - input.expect_comma()?; - ListStyleType::parse(input) - }) - .unwrap_or(ListStyleType::Decimal) - } +/// A computed content item. +pub type ContentItem = generics::ContentItem; - #[cfg(feature = "gecko")] - fn parse_counter_style(context: &ParserContext, input: &mut Parser) -> CounterStyleOrNone { - input - .try(|input| { - input.expect_comma()?; - CounterStyleOrNone::parse(context, input) - }) - .unwrap_or(CounterStyleOrNone::decimal()) - } -} - -impl Parse for Content { - // normal | none | [ | | open-quote | close-quote | no-open-quote | - // no-close-quote ]+ - // TODO: , attr() - fn parse<'i, 't>( - _context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - if input - .try(|input| input.expect_ident_matching("normal")) - .is_ok() - { - return Ok(Content::Normal); - } - if input - .try(|input| input.expect_ident_matching("none")) - .is_ok() - { - return Ok(Content::None); - } - #[cfg(feature = "gecko")] - { - if input - .try(|input| input.expect_ident_matching("-moz-alt-content")) - .is_ok() - { - return Ok(Content::MozAltContent); - } - } - - let mut content = vec![]; - loop { - #[cfg(feature = "gecko")] - { - if let Ok(url) = input.try(|i| SpecifiedImageUrl::parse(_context, i)) { - content.push(ContentItem::Url(url)); - continue; - } - } - // FIXME: remove clone() when lifetimes are non-lexical - match input.next().map(|t| t.clone()) { - Ok(Token::QuotedString(ref value)) => { - content.push(ContentItem::String( - value.as_ref().to_owned().into_boxed_str(), - )); - }, - Ok(Token::Function(ref name)) => { - let result = match_ignore_ascii_case! { &name, - "counter" => Some(input.parse_nested_block(|input| { - let location = input.current_source_location(); - let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?; - #[cfg(feature = "servo")] - let style = Content::parse_counter_style(input); - #[cfg(feature = "gecko")] - let style = Content::parse_counter_style(_context, input); - Ok(ContentItem::Counter(name, style)) - })), - "counters" => Some(input.parse_nested_block(|input| { - let location = input.current_source_location(); - let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?; - input.expect_comma()?; - let separator = input.expect_string()?.as_ref().to_owned().into_boxed_str(); - #[cfg(feature = "servo")] - let style = Content::parse_counter_style(input); - #[cfg(feature = "gecko")] - let style = Content::parse_counter_style(_context, input); - Ok(ContentItem::Counters(name, separator, style)) - })), - #[cfg(feature = "gecko")] - "attr" => Some(input.parse_nested_block(|input| { - Ok(ContentItem::Attr(Attr::parse_function(_context, input)?)) - })), - _ => None - }; - match result { - Some(result) => content.push(result?), - None => { - return Err(input.new_custom_error( - StyleParseErrorKind::UnexpectedFunction(name.clone()), - )) - }, - } - }, - Ok(Token::Ident(ref ident)) => { - content.push(match_ignore_ascii_case! { &ident, - "open-quote" => ContentItem::OpenQuote, - "close-quote" => ContentItem::CloseQuote, - "no-open-quote" => ContentItem::NoOpenQuote, - "no-close-quote" => ContentItem::NoCloseQuote, - _ => return Err(input.new_custom_error( - SelectorParseErrorKind::UnexpectedIdent(ident.clone()))) - }); - }, - Err(_) => break, - Ok(t) => return Err(input.new_unexpected_token_error(t)), - } - } - if content.is_empty() { - return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); - } - Ok(Content::Items(content.into_boxed_slice())) - } -} diff --git a/components/style/values/computed/effects.rs b/components/style/values/computed/effects.rs index 92e91f163f0..3d804d42605 100644 --- a/components/style/values/computed/effects.rs +++ b/components/style/values/computed/effects.rs @@ -9,6 +9,8 @@ use values::Impossible; use values::computed::{Angle, NonNegativeNumber}; use values::computed::color::RGBAColor; use values::computed::length::{Length, NonNegativeLength}; +#[cfg(feature = "gecko")] +use values::computed::url::ComputedUrl; use values::generics::effects::BoxShadow as GenericBoxShadow; use values::generics::effects::Filter as GenericFilter; use values::generics::effects::SimpleShadow as GenericSimpleShadow; @@ -18,11 +20,11 @@ pub type BoxShadow = GenericBoxShadow, Length, NonNegativeLeng /// A computed value for a single `filter`. #[cfg(feature = "gecko")] -pub type Filter = GenericFilter; +pub type Filter = GenericFilter; /// A computed value for a single `filter`. #[cfg(not(feature = "gecko"))] -pub type Filter = GenericFilter; +pub type Filter = GenericFilter; /// A computed value for the `drop-shadow()` filter. pub type SimpleShadow = GenericSimpleShadow, Length, NonNegativeLength>; diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 4adf33253e8..0f27225eeb0 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -56,6 +56,7 @@ pub use self::inherited_box::{ImageOrientation, Orientation}; #[cfg(feature = "gecko")] pub use self::gecko::ScrollSnapPoint; pub use self::rect::LengthOrNumberRect; +pub use self::resolution::Resolution; pub use super::{Auto, Either, None_}; pub use super::specified::{BorderStyle, TextDecorationLine}; pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage}; @@ -67,9 +68,6 @@ pub use self::list::Quotes; pub use self::list::ListStyleType; pub use self::outline::OutlineStyle; pub use self::percentage::{Percentage, NonNegativePercentage}; -pub use self::pointing::{CaretColor, Cursor}; -#[cfg(feature = "gecko")] -pub use self::pointing::CursorImage; pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; @@ -80,7 +78,9 @@ pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle, TextOve pub use self::time::Time; pub use self::transform::{Rotate, Scale, TimingFunction, Transform, TransformOperation}; pub use self::transform::{TransformOrigin, TransformStyle, Translate}; -pub use self::ui::MozForceBrokenImageIcon; +pub use self::ui::{CaretColor, Cursor, MozForceBrokenImageIcon}; +#[cfg(feature = "gecko")] +pub use self::ui::CursorImage; #[cfg(feature = "gecko")] pub mod align; @@ -104,9 +104,9 @@ pub mod length; pub mod list; pub mod outline; pub mod percentage; -pub mod pointing; pub mod position; pub mod rect; +pub mod resolution; pub mod svg; pub mod table; pub mod text; diff --git a/components/style/values/computed/pointing.rs b/components/style/values/computed/pointing.rs deleted file mode 100644 index a89db9104c3..00000000000 --- a/components/style/values/computed/pointing.rs +++ /dev/null @@ -1,21 +0,0 @@ -/* 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 values for Pointing properties. -//! -//! https://drafts.csswg.org/css-ui/#pointing-keyboard - -use values::computed::Number; -use values::computed::color::Color; -use values::computed::url::ComputedImageUrl; -use values::generics::pointing as generics; - -/// A computed value for the `caret-color` property. -pub type CaretColor = generics::CaretColor; - -/// A computed value for the `cursor` property. -pub type Cursor = generics::Cursor; - -/// A computed value for item of `image cursors`. -pub type CursorImage = generics::CursorImage; diff --git a/components/style/values/computed/resolution.rs b/components/style/values/computed/resolution.rs new file mode 100644 index 00000000000..817ba082236 --- /dev/null +++ b/components/style/values/computed/resolution.rs @@ -0,0 +1,48 @@ +/* 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/. */ + +//! Resolution values: +//! +//! https://drafts.csswg.org/css-values/#resolution + +use std::fmt::{self, Write}; +use style_traits::{CssWriter, ToCss}; +use values::CSSFloat; +use values::computed::{Context, ToComputedValue}; +use values::specified; + +/// A computed ``. +pub struct Resolution(CSSFloat); + +impl Resolution { + /// Returns this resolution value as dppx. + #[inline] + pub fn dppx(&self) -> CSSFloat { + self.0 + } +} + +impl ToComputedValue for specified::Resolution { + type ComputedValue = Resolution; + + #[inline] + fn to_computed_value(&self, _: &Context) -> Self::ComputedValue { + Resolution(self.to_dppx()) + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + specified::Resolution::Dppx(computed.dppx()) + } +} + +impl ToCss for Resolution { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: fmt::Write, + { + self.dppx().to_css(dest)?; + dest.write_str("dppx") + } +} diff --git a/components/style/values/computed/ui.rs b/components/style/values/computed/ui.rs index f3f3cdf4c99..1313a5e5dd9 100644 --- a/components/style/values/computed/ui.rs +++ b/components/style/values/computed/ui.rs @@ -4,4 +4,18 @@ //! Computed values for UI properties +use values::computed::Number; +use values::computed::color::Color; +use values::computed::url::ComputedImageUrl; +use values::generics::ui as generics; + pub use values::specified::ui::MozForceBrokenImageIcon; + +/// A computed value for the `caret-color` property. +pub type CaretColor = generics::CaretColor; + +/// A computed value for the `cursor` property. +pub type Cursor = generics::Cursor; + +/// A computed value for item of `image cursors`. +pub type CursorImage = generics::CursorImage; diff --git a/components/style/values/generics/counters.rs b/components/style/values/generics/counters.rs index 9f50ab1e2b0..66da2625ffd 100644 --- a/components/style/values/generics/counters.rs +++ b/components/style/values/generics/counters.rs @@ -4,8 +4,14 @@ //! Generic types for counters-related CSS values. +#[cfg(feature = "servo")] +use computed_values::list_style_type::T as ListStyleType; use std::ops::Deref; use values::CustomIdent; +#[cfg(feature = "gecko")] +use values::generics::CounterStyleOrNone; +#[cfg(feature = "gecko")] +use values::specified::Attr; /// A name / value pair for counters. #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, @@ -74,3 +80,78 @@ impl Default for Counters { Counters(vec![].into_boxed_slice()) } } + +#[cfg(feature = "servo")] +type CounterStyleType = ListStyleType; + +#[cfg(feature = "gecko")] +type CounterStyleType = CounterStyleOrNone; + +#[cfg(feature = "servo")] +#[inline] +fn is_decimal(counter_type: &CounterStyleType) -> bool { + *counter_type == ListStyleType::Decimal +} + +#[cfg(feature = "gecko")] +#[inline] +fn is_decimal(counter_type: &CounterStyleType) -> bool { + *counter_type == CounterStyleOrNone::decimal() +} + +/// The specified value for the `content` property. +/// +/// https://drafts.csswg.org/css-content/#propdef-content +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] +pub enum Content { + /// `normal` reserved keyword. + Normal, + /// `none` reserved keyword. + None, + /// `-moz-alt-content`. + #[cfg(feature = "gecko")] + MozAltContent, + /// Content items. + Items(#[css(iterable)] Box<[ContentItem]>), +} + +impl Content { + /// Set `content` property to `normal`. + #[inline] + pub fn normal() -> Self { + Content::Normal + } + +} + +/// Items for the `content` property. +#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, + ToComputedValue, ToCss)] +pub enum ContentItem { + /// Literal string content. + String(Box), + /// `counter(name, style)`. + #[css(comma, function)] + Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyleType), + /// `counters(name, separator, style)`. + #[css(comma, function)] + Counters( + CustomIdent, + Box, + #[css(skip_if = "is_decimal")] CounterStyleType, + ), + /// `open-quote`. + OpenQuote, + /// `close-quote`. + CloseQuote, + /// `no-open-quote`. + NoOpenQuote, + /// `no-close-quote`. + NoCloseQuote, + /// `attr([namespace? `|`]? ident)` + #[cfg(feature = "gecko")] + Attr(Attr), + /// `url(url)` + Url(ImageUrl), +} diff --git a/components/style/values/generics/effects.rs b/components/style/values/generics/effects.rs index e5ee10fcada..f05dfe82d66 100644 --- a/components/style/values/generics/effects.rs +++ b/components/style/values/generics/effects.rs @@ -4,9 +4,6 @@ //! Generic types for CSS values related to effects. -#[cfg(feature = "gecko")] -use values::specified::url::SpecifiedUrl; - /// A generic value for a single `box-shadow`. #[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToCss)] @@ -23,9 +20,10 @@ pub struct BoxShadow { /// A generic value for a single `filter`. #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] +#[animation(no_bound(Url))] #[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)] -pub enum Filter { +pub enum Filter { /// `blur()` #[css(function)] Blur(Length), @@ -58,8 +56,7 @@ pub enum Filter { DropShadow(DropShadow), /// `` #[animation(error)] - #[cfg(feature = "gecko")] - Url(SpecifiedUrl), + Url(Url), } /// A generic value for the `drop-shadow()` filter and the `text-shadow` property. diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 59d9748ea5b..c68ed91426a 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -26,13 +26,13 @@ pub mod font; pub mod gecko; pub mod grid; pub mod image; -pub mod pointing; pub mod position; pub mod rect; pub mod size; pub mod svg; pub mod text; pub mod transform; +pub mod ui; pub mod url; // https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type diff --git a/components/style/values/generics/pointing.rs b/components/style/values/generics/ui.rs similarity index 98% rename from components/style/values/generics/pointing.rs rename to components/style/values/generics/ui.rs index 9d9ec031225..a52ee9fcf76 100644 --- a/components/style/values/generics/pointing.rs +++ b/components/style/values/generics/ui.rs @@ -2,7 +2,7 @@ * 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/. */ -//! Generic values for pointing properties. +//! Generic values for UI properties. use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; diff --git a/components/style/values/specified/counters.rs b/components/style/values/specified/counters.rs index 3daf8ee56a0..ea369f9dec7 100644 --- a/components/style/values/specified/counters.rs +++ b/components/style/values/specified/counters.rs @@ -8,17 +8,18 @@ use computed_values::list_style_type::T as ListStyleType; use cssparser::{Parser, Token}; use parser::{Parse, ParserContext}; +use selectors::parser::SelectorParseErrorKind; use style_traits::{ParseError, StyleParseErrorKind}; use values::CustomIdent; #[cfg(feature = "gecko")] use values::generics::CounterStyleOrNone; +use values::generics::counters as generics; use values::generics::counters::CounterIncrement as GenericCounterIncrement; use values::generics::counters::CounterPair; use values::generics::counters::CounterReset as GenericCounterReset; #[cfg(feature = "gecko")] use values::specified::Attr; use values::specified::Integer; -#[cfg(feature = "gecko")] use values::specified::url::SpecifiedImageUrl; /// A specified value for the `counter-increment` property. @@ -79,69 +80,129 @@ fn parse_counters<'i, 't>( } } -#[cfg(feature = "servo")] -type CounterStyleType = ListStyleType; - -#[cfg(feature = "gecko")] -type CounterStyleType = CounterStyleOrNone; - -#[cfg(feature = "servo")] -#[inline] -fn is_decimal(counter_type: &CounterStyleType) -> bool { - *counter_type == ListStyleType::Decimal -} - -#[cfg(feature = "gecko")] -#[inline] -fn is_decimal(counter_type: &CounterStyleType) -> bool { - *counter_type == CounterStyleOrNone::decimal() -} - /// The specified value for the `content` property. -/// -/// https://drafts.csswg.org/css-content/#propdef-content -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue, ToCss)] -pub enum Content { - /// `normal` reserved keyword. - Normal, - /// `none` reserved keyword. - None, - /// `-moz-alt-content`. +pub type Content = generics::Content; + +/// The specified value for a content item in the `content` property. +pub type ContentItem = generics::ContentItem; + +impl Content { + #[cfg(feature = "servo")] + fn parse_counter_style(_: &ParserContext, input: &mut Parser) -> ListStyleType { + input + .try(|input| { + input.expect_comma()?; + ListStyleType::parse(input) + }) + .unwrap_or(ListStyleType::Decimal) + } + #[cfg(feature = "gecko")] - MozAltContent, - /// Content items. - Items(#[css(iterable)] Box<[ContentItem]>), + fn parse_counter_style(context: &ParserContext, input: &mut Parser) -> CounterStyleOrNone { + input + .try(|input| { + input.expect_comma()?; + CounterStyleOrNone::parse(context, input) + }) + .unwrap_or(CounterStyleOrNone::decimal()) + } } -/// Items for the `content` property. -#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToComputedValue, ToCss)] -pub enum ContentItem { - /// Literal string content. - String(Box), - /// `counter(name, style)`. - #[css(comma, function)] - Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyleType), - /// `counters(name, separator, style)`. - #[css(comma, function)] - Counters( - CustomIdent, - Box, - #[css(skip_if = "is_decimal")] CounterStyleType, - ), - /// `open-quote`. - OpenQuote, - /// `close-quote`. - CloseQuote, - /// `no-open-quote`. - NoOpenQuote, - /// `no-close-quote`. - NoCloseQuote, - /// `attr([namespace? `|`]? ident)` - #[cfg(feature = "gecko")] - Attr(Attr), - /// `url(url)` - #[cfg(feature = "gecko")] - Url(SpecifiedImageUrl), +impl Parse for Content { + // normal | none | [ | | open-quote | close-quote | no-open-quote | + // no-close-quote ]+ + // TODO: , attr() + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + if input + .try(|input| input.expect_ident_matching("normal")) + .is_ok() + { + return Ok(generics::Content::Normal); + } + if input + .try(|input| input.expect_ident_matching("none")) + .is_ok() + { + return Ok(generics::Content::None); + } + #[cfg(feature = "gecko")] + { + if input + .try(|input| input.expect_ident_matching("-moz-alt-content")) + .is_ok() + { + return Ok(generics::Content::MozAltContent); + } + } + + let mut content = vec![]; + loop { + #[cfg(feature = "gecko")] + { + if let Ok(url) = input.try(|i| SpecifiedImageUrl::parse(context, i)) { + content.push(generics::ContentItem::Url(url)); + continue; + } + } + // FIXME: remove clone() when lifetimes are non-lexical + match input.next().map(|t| t.clone()) { + Ok(Token::QuotedString(ref value)) => { + content.push(generics::ContentItem::String( + value.as_ref().to_owned().into_boxed_str(), + )); + }, + Ok(Token::Function(ref name)) => { + let result = match_ignore_ascii_case! { &name, + "counter" => Some(input.parse_nested_block(|input| { + let location = input.current_source_location(); + let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?; + let style = Content::parse_counter_style(context, input); + Ok(generics::ContentItem::Counter(name, style)) + })), + "counters" => Some(input.parse_nested_block(|input| { + let location = input.current_source_location(); + let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?; + input.expect_comma()?; + let separator = input.expect_string()?.as_ref().to_owned().into_boxed_str(); + let style = Content::parse_counter_style(context, input); + Ok(generics::ContentItem::Counters(name, separator, style)) + })), + #[cfg(feature = "gecko")] + "attr" => Some(input.parse_nested_block(|input| { + Ok(generics::ContentItem::Attr(Attr::parse_function(context, input)?)) + })), + _ => None + }; + match result { + Some(result) => content.push(result?), + None => { + return Err(input.new_custom_error( + StyleParseErrorKind::UnexpectedFunction(name.clone()), + )) + }, + } + }, + Ok(Token::Ident(ref ident)) => { + content.push(match_ignore_ascii_case! { &ident, + "open-quote" => generics::ContentItem::OpenQuote, + "close-quote" => generics::ContentItem::CloseQuote, + "no-open-quote" => generics::ContentItem::NoOpenQuote, + "no-close-quote" => generics::ContentItem::NoCloseQuote, + _ => return Err(input.new_custom_error( + SelectorParseErrorKind::UnexpectedIdent(ident.clone()) + )) + }); + }, + Err(_) => break, + Ok(t) => return Err(input.new_unexpected_token_error(t)), + } + } + if content.is_empty() { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + Ok(generics::Content::Items(content.into_boxed_slice())) + } } diff --git a/components/style/values/specified/effects.rs b/components/style/values/specified/effects.rs index 86464f1ba0c..f10b53fa788 100644 --- a/components/style/values/specified/effects.rs +++ b/components/style/values/specified/effects.rs @@ -28,11 +28,11 @@ pub type BoxShadow = /// A specified value for a single `filter`. #[cfg(feature = "gecko")] -pub type Filter = GenericFilter; +pub type Filter = GenericFilter; /// A specified value for a single `filter`. #[cfg(not(feature = "gecko"))] -pub type Filter = GenericFilter; +pub type Filter = GenericFilter; /// A value for the `` parts in `Filter`. #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 3f89dae0053..b1795acd65b 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -61,10 +61,8 @@ pub use self::list::Quotes; pub use self::list::ListStyleType; pub use self::outline::OutlineStyle; pub use self::rect::LengthOrNumberRect; +pub use self::resolution::Resolution; pub use self::percentage::Percentage; -pub use self::pointing::{CaretColor, Cursor}; -#[cfg(feature = "gecko")] -pub use self::pointing::CursorImage; pub use self::position::{GridAutoFlow, GridTemplateAreas, Position}; pub use self::position::{PositionComponent, ZIndex}; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; @@ -77,7 +75,9 @@ pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpa pub use self::time::Time; pub use self::transform::{Rotate, Scale, TimingFunction, Transform}; pub use self::transform::{TransformOrigin, TransformStyle, Translate}; -pub use self::ui::MozForceBrokenImageIcon; +pub use self::ui::{CaretColor, Cursor, MozForceBrokenImageIcon}; +#[cfg(feature = "gecko")] +pub use self::ui::CursorImage; pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; #[cfg(feature = "gecko")] @@ -104,9 +104,9 @@ pub mod length; pub mod list; pub mod outline; pub mod percentage; -pub mod pointing; pub mod position; pub mod rect; +pub mod resolution; pub mod source_size_list; pub mod svg; pub mod table; diff --git a/components/style/values/specified/pointing.rs b/components/style/values/specified/pointing.rs deleted file mode 100644 index cf718a1fd9d..00000000000 --- a/components/style/values/specified/pointing.rs +++ /dev/null @@ -1,86 +0,0 @@ -/* 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 values for Pointing properties. -//! -//! https://drafts.csswg.org/css-ui/#pointing-keyboard - -use cssparser::Parser; -use parser::{Parse, ParserContext}; -use style_traits::{ParseError, StyleParseErrorKind}; -use style_traits::cursor::CursorKind; -use values::generics::pointing as generics; -use values::specified::Number; -use values::specified::color::Color; -use values::specified::url::SpecifiedImageUrl; - -/// A specified value for the `caret-color` property. -pub type CaretColor = generics::CaretColor; - -impl Parse for CaretColor { - fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - if input.try(|i| i.expect_ident_matching("auto")).is_ok() { - return Ok(generics::CaretColor::Auto); - } - Ok(generics::CaretColor::Color(Color::parse(context, input)?)) - } -} - -/// A specified value for the `cursor` property. -pub type Cursor = generics::Cursor; - -/// A specified value for item of `image cursors`. -pub type CursorImage = generics::CursorImage; - -impl Parse for Cursor { - /// cursor: [ [ ]?]# [auto | default | ...] - fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - let mut images = vec![]; - loop { - match input.try(|input| CursorImage::parse(context, input)) { - Ok(image) => images.push(image), - Err(_) => break, - } - input.expect_comma()?; - } - Ok(Self { - images: images.into_boxed_slice(), - keyword: CursorKind::parse(context, input)?, - }) - } -} - -impl Parse for CursorKind { - fn parse<'i, 't>( - _context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - let location = input.current_source_location(); - let ident = input.expect_ident()?; - CursorKind::from_css_keyword(&ident).map_err(|_| { - location.new_custom_error(StyleParseErrorKind::UnspecifiedError) - }) - } -} - -impl Parse for CursorImage { - fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - Ok(Self { - url: SpecifiedImageUrl::parse(context, input)?, - hotspot: match input.try(|input| Number::parse(context, input)) { - Ok(number) => Some((number, Number::parse(context, input)?)), - Err(_) => None, - }, - }) - } -} diff --git a/components/style/values/specified/resolution.rs b/components/style/values/specified/resolution.rs new file mode 100644 index 00000000000..52da8eaea34 --- /dev/null +++ b/components/style/values/specified/resolution.rs @@ -0,0 +1,79 @@ +/* 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/. */ + +//! Resolution values: +//! +//! https://drafts.csswg.org/css-values/#resolution + +use cssparser::{Parser, Token}; +use parser::{Parse, ParserContext}; +use style_traits::{ParseError, StyleParseErrorKind}; +use values::CSSFloat; + +/// A specified resolution. +#[derive(Clone, Debug, PartialEq, ToCss)] +pub enum Resolution { + /// Dots per inch. + #[css(dimension)] + Dpi(CSSFloat), + /// An alias unit for dots per pixel. + #[css(dimension)] + X(CSSFloat), + /// Dots per pixel. + #[css(dimension)] + Dppx(CSSFloat), + /// Dots per centimeter. + #[css(dimension)] + Dpcm(CSSFloat), +} + +impl Resolution { + /// Convert this resolution value to dppx units. + pub fn to_dppx(&self) -> CSSFloat { + match *self { + Resolution::X(f) | + Resolution::Dppx(f) => f, + _ => self.to_dpi() / 96.0, + } + } + + /// Convert this resolution value to dpi units. + pub fn to_dpi(&self) -> CSSFloat { + match *self { + Resolution::Dpi(f) => f, + Resolution::X(f) | + Resolution::Dppx(f) => f * 96.0, + Resolution::Dpcm(f) => f * 2.54, + } + } +} + +impl Parse for Resolution { + fn parse<'i, 't>( + _: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let location = input.current_source_location(); + let (value, unit) = match *input.next()? { + Token::Dimension { + value, ref unit, .. + } => (value, unit), + ref t => return Err(location.new_unexpected_token_error(t.clone())), + }; + + if value <= 0. { + return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + + match_ignore_ascii_case! { &unit, + "dpi" => Ok(Resolution::Dpi(value)), + "dppx" => Ok(Resolution::Dppx(value)), + "dpcm" => Ok(Resolution::Dpcm(value)), + "x" => Ok(Resolution::X(value)), + _ => Err(location.new_custom_error( + StyleParseErrorKind::UnexpectedDimension(unit.clone()) + )), + } + } +} diff --git a/components/style/values/specified/ui.rs b/components/style/values/specified/ui.rs index fc7ef048082..d42b1e4e257 100644 --- a/components/style/values/specified/ui.rs +++ b/components/style/values/specified/ui.rs @@ -8,6 +8,81 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +use style_traits::cursor::CursorKind; +use values::generics::ui as generics; +use values::specified::Number; +use values::specified::color::Color; +use values::specified::url::SpecifiedImageUrl; + +/// A specified value for the `caret-color` property. +pub type CaretColor = generics::CaretColor; + +impl Parse for CaretColor { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + if input.try(|i| i.expect_ident_matching("auto")).is_ok() { + return Ok(generics::CaretColor::Auto); + } + Ok(generics::CaretColor::Color(Color::parse(context, input)?)) + } +} + +/// A specified value for the `cursor` property. +pub type Cursor = generics::Cursor; + +/// A specified value for item of `image cursors`. +pub type CursorImage = generics::CursorImage; + +impl Parse for Cursor { + /// cursor: [ [ ]?]# [auto | default | ...] + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let mut images = vec![]; + loop { + match input.try(|input| CursorImage::parse(context, input)) { + Ok(image) => images.push(image), + Err(_) => break, + } + input.expect_comma()?; + } + Ok(Self { + images: images.into_boxed_slice(), + keyword: CursorKind::parse(context, input)?, + }) + } +} + +impl Parse for CursorKind { + fn parse<'i, 't>( + _context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let location = input.current_source_location(); + let ident = input.expect_ident()?; + CursorKind::from_css_keyword(&ident).map_err(|_| { + location.new_custom_error(StyleParseErrorKind::UnspecifiedError) + }) + } +} + +impl Parse for CursorImage { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + Ok(Self { + url: SpecifiedImageUrl::parse(context, input)?, + hotspot: match input.try(|input| Number::parse(context, input)) { + Ok(number) => Some((number, Number::parse(context, input)?)), + Err(_) => None, + }, + }) + } +} /// Specified value of `-moz-force-broken-image-icon` #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs index 29b8eee58ea..8b3bd13dc20 100644 --- a/components/style_traits/values.rs +++ b/components/style_traits/values.rs @@ -401,6 +401,7 @@ macro_rules! impl_to_css_for_predefined_type { } impl_to_css_for_predefined_type!(f32); +impl_to_css_for_predefined_type!(i8); impl_to_css_for_predefined_type!(i32); impl_to_css_for_predefined_type!(u16); impl_to_css_for_predefined_type!(u32);