From ef28ccb1a32290115e14f1cb46b7f56bbf307657 Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Mon, 16 Oct 2017 18:01:42 +0800 Subject: [PATCH] style: Add FFI function for parsing IntersectionObserver rootMargin values. --- .../gecko_bindings/sugar/ns_css_value.rs | 14 +++- components/style/values/specified/gecko.rs | 71 ++++++++++++++++++- ports/geckolib/glue.rs | 40 ++++++++++- 3 files changed, 120 insertions(+), 5 deletions(-) diff --git a/components/style/gecko_bindings/sugar/ns_css_value.rs b/components/style/gecko_bindings/sugar/ns_css_value.rs index 9c57b788ef13..8c1d83c8ffda 100644 --- a/components/style/gecko_bindings/sugar/ns_css_value.rs +++ b/components/style/gecko_bindings/sugar/ns_css_value.rs @@ -75,10 +75,10 @@ impl nsCSSValue { pub unsafe fn set_lop(&mut self, lop: LengthOrPercentage) { match lop { LengthOrPercentage::Length(px) => { - bindings::Gecko_CSSValue_SetPixelLength(self, px.px()) + self.set_px(px.px()) } LengthOrPercentage::Percentage(pc) => { - bindings::Gecko_CSSValue_SetPercentage(self, pc.0) + self.set_percentage(pc.0) } LengthOrPercentage::Calc(calc) => { bindings::Gecko_CSSValue_SetCalc(self, calc.into()) @@ -86,6 +86,16 @@ impl nsCSSValue { } } + /// Sets a px value to this nsCSSValue. + pub unsafe fn set_px(&mut self, px: f32) { + bindings::Gecko_CSSValue_SetPixelLength(self, px) + } + + /// Sets a percentage value to this nsCSSValue. + pub unsafe fn set_percentage(&mut self, unit_value: f32) { + bindings::Gecko_CSSValue_SetPercentage(self, unit_value) + } + /// Returns LengthOrPercentage value. pub unsafe fn get_lop(&self) -> LengthOrPercentage { use values::computed::Length; diff --git a/components/style/values/specified/gecko.rs b/components/style/values/specified/gecko.rs index 507a3b160deb..b36cd582aed0 100644 --- a/components/style/values/specified/gecko.rs +++ b/components/style/values/specified/gecko.rs @@ -4,10 +4,15 @@ //! Specified types for legacy Gecko-only properties. -use cssparser::Parser; +use cssparser::{Parser, Token}; +use gecko_bindings::structs; +use gecko_bindings::sugar::ns_css_value::ToNsCssValue; use parser::{Parse, ParserContext}; -use style_traits::ParseError; +use style_traits::{ParseError, StyleParseErrorKind}; +use values::CSSFloat; +use values::computed; use values::generics::gecko::ScrollSnapPoint as GenericScrollSnapPoint; +use values::generics::rect::Rect; use values::specified::length::LengthOrPercentage; /// A specified type for scroll snap points. @@ -25,3 +30,65 @@ impl Parse for ScrollSnapPoint { Ok(GenericScrollSnapPoint::Repeat(length)) } } + +/// A component of an IntersectionObserverRootMargin. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum PixelOrPercentage { + /// An absolute length in pixels (px) + Px(CSSFloat), + /// A percentage (%) + Percentage(computed::Percentage), +} + +impl Parse for PixelOrPercentage { + fn parse<'i, 't>( + _context: &ParserContext, + input: &mut Parser<'i, 't> + ) -> Result> { + let location = input.current_source_location(); + let token = input.next()?; + let value = match *token { + Token::Dimension { value, ref unit, .. } => { + match_ignore_ascii_case! { unit, + "px" => Ok(PixelOrPercentage::Px(value)), + _ => Err(()), + } + } + Token::Percentage { unit_value, .. } => { + Ok(PixelOrPercentage::Percentage( + computed::Percentage(unit_value) + )) + } + _ => Err(()), + }; + value.map_err(|()| { + location.new_custom_error(StyleParseErrorKind::UnspecifiedError) + }) + } +} + +impl ToNsCssValue for PixelOrPercentage { + fn convert(self, nscssvalue: &mut structs::nsCSSValue) { + match self { + PixelOrPercentage::Px(px) => { + unsafe { nscssvalue.set_px(px); } + } + PixelOrPercentage::Percentage(pc) => { + unsafe { nscssvalue.set_percentage(pc.0); } + } + } + } +} + +/// The value of an IntersectionObserver's rootMargin property. +pub struct IntersectionObserverRootMargin(pub Rect); + +impl Parse for IntersectionObserverRootMargin { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let rect = Rect::parse_with(context, input, PixelOrPercentage::parse)?; + Ok(IntersectionObserverRootMargin(rect)) + } +} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 9e7c2f22f2d3..c1b0f7a8445c 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -112,7 +112,7 @@ use style::gecko_bindings::sugar::refptr::RefPtr; use style::gecko_properties::style_structs; use style::invalidation::element::restyle_hints; use style::media_queries::{Device, MediaList, parse_media_query_list}; -use style::parser::{ParserContext, self}; +use style::parser::{Parse, ParserContext, self}; use style::properties::{CascadeFlags, ComputedValues, DeclarationSource, Importance}; use style::properties::{IS_FIELDSET_CONTENT, IS_LINK, IS_VISITED_LINK, LonghandIdSet}; use style::properties::{LonghandId, PropertyDeclaration, PropertyDeclarationBlock, PropertyId}; @@ -146,6 +146,7 @@ use style::values::animated::{Animate, Procedure, ToAnimatedZero}; use style::values::computed::{Context, ToComputedValue}; use style::values::distance::ComputeSquaredDistance; use style::values::specified; +use style::values::specified::gecko::IntersectionObserverRootMargin; use style_traits::{PARSING_MODE_DEFAULT, ToCss}; use super::error_reporter::ErrorReporter; use super::stylesheet_loader::StylesheetLoader; @@ -2212,6 +2213,7 @@ pub extern "C" fn Servo_ParseEasing( ) -> bool { use style::properties::longhands::transition_timing_function; + // FIXME Dummy URL data would work fine here. let url_data = unsafe { RefPtr::from_ptr_ref(&data) }; let context = ParserContext::new(Origin::Author, url_data, @@ -4270,3 +4272,39 @@ pub extern "C" fn Servo_ComputeColor( Err(_) => false, } } + +#[no_mangle] +pub extern "C" fn Servo_ParseIntersectionObserverRootMargin( + value: *const nsAString, + result: *mut structs::nsCSSRect, +) -> bool { + let value = unsafe { value.as_ref().unwrap().to_string() }; + let result = unsafe { result.as_mut().unwrap() }; + + let mut input = ParserInput::new(&value); + let mut parser = Parser::new(&mut input); + + let url_data = unsafe { dummy_url_data() }; + let context = ParserContext::new( + Origin::Author, + url_data, + Some(CssRuleType::Style), + PARSING_MODE_DEFAULT, + QuirksMode::NoQuirks, + ); + + let margin = parser.parse_entirely(|p| { + IntersectionObserverRootMargin::parse(&context, p) + }); + match margin { + Ok(margin) => { + let rect = margin.0; + result.mTop.set_from(rect.0); + result.mRight.set_from(rect.1); + result.mBottom.set_from(rect.2); + result.mLeft.set_from(rect.3); + true + } + Err(..) => false, + } +}