diff options
22 files changed, 267 insertions, 187 deletions
diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 086b323e878..8841b1ab3e9 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -1205,9 +1205,9 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> -> ConstructionResult { let flotation = FloatKind::from_property(flotation); let marker_fragments = match node.style(self.style_context()).get_list().list_style_image { - list_style_image::T::Url(ref url, ref _extra_data) => { + list_style_image::T::Url(ref url_value) => { let image_info = box ImageFragmentInfo::new(node, - Some((*url).clone()), + url_value.url().map(|u| (**u).clone()), &self.layout_context.shared); vec![Fragment::new(node, SpecificFragmentInfo::Image(image_info), self.layout_context)] } diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index ec881ea9bcb..d5f3317cee5 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -612,14 +612,16 @@ impl FragmentDisplayListBuilding for Fragment { style); } } - Some(computed::Image::Url(ref image_url, ref _extra_data)) => { - self.build_display_list_for_background_image(state, - style, - display_list_section, - &bounds, - &clip, - image_url, - i); + Some(computed::Image::Url(ref image_url)) => { + if let Some(url) = image_url.url() { + self.build_display_list_for_background_image(state, + style, + display_list_section, + &bounds, + &clip, + url, + i); + } } } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 15a4ef816c8..ac65c01e24c 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -368,7 +368,7 @@ impl LayoutElementHelpers for LayoutJS<Element> { PropertyDeclaration::BackgroundImage(DeclaredValue::Value( background_image::SpecifiedValue(vec![ background_image::single_value::SpecifiedValue(Some( - specified::Image::Url(url, specified::UrlExtraData { }) + specified::Image::for_cascade(Some(Arc::new(url)), specified::url::UrlExtraData { }) )) ]))))); } diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 49c10625db3..3bae647c7b2 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -2528,7 +2528,6 @@ dependencies = [ "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index c002ebf86e7..6202b5f852f 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -120,11 +120,13 @@ impl nsStyleImage { Image::Gradient(gradient) => { self.set_gradient(gradient) }, - Image::Url(ref url, ref extra_data) if with_url => { + Image::Url(ref url) if with_url => { + let (ptr, len) = url.as_slice_components(); + let extra_data = url.extra_data(); unsafe { Gecko_SetUrlImageValue(self, - url.as_str().as_ptr(), - url.as_str().len() as u32, + ptr, + len as u32, extra_data.base.get(), extra_data.referrer.get(), extra_data.principal.get()); diff --git a/components/style/parser.rs b/components/style/parser.rs index 1cf46a80d09..84d421b9ee6 100644 --- a/components/style/parser.rs +++ b/components/style/parser.rs @@ -66,15 +66,6 @@ impl<'a> ParserContext<'a> { } } - -impl<'a> ParserContext<'a> { - pub fn parse_url(&self, input: &str) -> Url { - self.base_url.join(input) - .unwrap_or_else(|_| Url::parse("about:invalid").unwrap()) - } -} - - /// Defaults to a no-op. /// Set a `RUST_LOG=style::errors` environment variable /// to log CSS parse errors to stderr. diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index cead90fc571..f1ecd7ffd13 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1036,11 +1036,13 @@ fn static_assert() { use properties::longhands::_moz_binding::computed_value::T as BindingValue; match v { BindingValue::None => debug_assert!(self.gecko.mBinding.mRawPtr.is_null()), - BindingValue::Url(ref url, ref extra_data) => { + BindingValue::Url(ref url) => { + let extra_data = url.extra_data(); + let (ptr, len) = url.as_slice_components(); unsafe { Gecko_SetMozBinding(&mut self.gecko, - url.as_str().as_ptr(), - url.as_str().len() as u32, + ptr, + len as u32, extra_data.base.get(), extra_data.referrer.get(), extra_data.principal.get()); @@ -1441,11 +1443,13 @@ fn static_assert() { Gecko_SetListStyleImageNone(&mut self.gecko); } } - UrlOrNone::Url(ref url, ref extra_data) => { + UrlOrNone::Url(ref url) => { + let (ptr, len) = url.as_slice_components(); + let extra_data = url.extra_data(); unsafe { Gecko_SetListStyleImage(&mut self.gecko, - url.as_str().as_ptr(), - url.as_str().len() as u32, + ptr, + len as u32, extra_data.base.get(), extra_data.referrer.get(), extra_data.principal.get()); diff --git a/components/style/properties/longhand/svg.mako.rs b/components/style/properties/longhand/svg.mako.rs index 9d6667a8d97..a0d107f6326 100644 --- a/components/style/properties/longhand/svg.mako.rs +++ b/components/style/properties/longhand/svg.mako.rs @@ -149,20 +149,21 @@ ${helpers.single_keyword("mask-composite", has_uncacheable_values="${product == 'gecko'}"> use std::fmt; use style_traits::ToCss; - use url::Url; - use values::specified::{Image, UrlExtraData}; + use std::sync::Arc; + use values::specified::Image; + use values::specified::url::SpecifiedUrl; use values::NoViewportPercentage; pub mod computed_value { use std::fmt; use style_traits::ToCss; - use url::Url; use values::computed; + use values::specified::url::SpecifiedUrl; #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum T { Image(computed::Image), - Url(Url, computed::UrlExtraData), + Url(SpecifiedUrl), None } @@ -171,7 +172,7 @@ ${helpers.single_keyword("mask-composite", match *self { T::None => dest.write_str("none"), T::Image(ref image) => image.to_css(dest), - T::Url(ref url, _) => url.to_css(dest), + T::Url(ref url) => url.to_css(dest), } } } @@ -183,7 +184,7 @@ ${helpers.single_keyword("mask-composite", #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum SpecifiedValue { Image(Image), - Url(Url, UrlExtraData), + Url(SpecifiedUrl), None } @@ -191,7 +192,7 @@ ${helpers.single_keyword("mask-composite", fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { SpecifiedValue::Image(ref image) => image.to_css(dest), - SpecifiedValue::Url(ref url, _) => url.to_css(dest), + SpecifiedValue::Url(ref url) => url.to_css(dest), SpecifiedValue::None => dest.write_str("none"), } } @@ -211,11 +212,16 @@ ${helpers.single_keyword("mask-composite", } else { let image = try!(Image::parse(context, input)); match image { - Image::Url(url, data) => { - if url.fragment().is_some() { - Ok(SpecifiedValue::Url(url, data)) + Image::Url(url_value) => { + let has_valid_url = match url_value.url() { + Some(url) => url.fragment().is_some(), + None => false, + }; + + if has_valid_url { + Ok(SpecifiedValue::Url(url_value)) } else { - Ok(SpecifiedValue::Image(Image::Url(url, data))) + Ok(SpecifiedValue::Image(Image::Url(url_value))) } } image => Ok(SpecifiedValue::Image(image)) @@ -231,8 +237,8 @@ ${helpers.single_keyword("mask-composite", SpecifiedValue::None => computed_value::T::None, SpecifiedValue::Image(ref image) => computed_value::T::Image(image.to_computed_value(context)), - SpecifiedValue::Url(ref url, ref data) => - computed_value::T::Url(url.clone(), data.clone()), + SpecifiedValue::Url(ref url) => + computed_value::T::Url(url.clone()), } } @@ -242,8 +248,8 @@ ${helpers.single_keyword("mask-composite", computed_value::T::None => SpecifiedValue::None, computed_value::T::Image(ref image) => SpecifiedValue::Image(ToComputedValue::from_computed_value(image)), - computed_value::T::Url(ref url, ref data) => - SpecifiedValue::Url(url.clone(), data.clone()), + computed_value::T::Url(ref url) => + SpecifiedValue::Url(url.clone()), } } } diff --git a/components/style/values/computed/basic_shape.rs b/components/style/values/computed/basic_shape.rs index d27fe94545b..6428022538f 100644 --- a/components/style/values/computed/basic_shape.rs +++ b/components/style/values/computed/basic_shape.rs @@ -10,17 +10,16 @@ use properties::shorthands::serialize_four_sides; use std::fmt; use style_traits::ToCss; -use url::Url; use values::computed::{BorderRadiusSize, LengthOrPercentage}; -use values::computed::UrlExtraData; use values::computed::position::Position; +use values::specified::url::SpecifiedUrl; pub use values::specified::basic_shape::{FillRule, GeometryBox, ShapeBox}; #[derive(Clone, PartialEq, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum ShapeSource<T> { - Url(Url, UrlExtraData), + Url(SpecifiedUrl), Shape(BasicShape, Option<T>), Box(T), None, @@ -35,7 +34,7 @@ impl<T> Default for ShapeSource<T> { impl<T: ToCss> ToCss for ShapeSource<T> { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { - ShapeSource::Url(ref url, _) => url.to_css(dest), + ShapeSource::Url(ref url) => url.to_css(dest), ShapeSource::Shape(ref shape, Some(ref reference)) => { try!(shape.to_css(dest)); try!(dest.write_str(" ")); diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs index 4b825d1fbdd..f99ed74ac5e 100644 --- a/components/style/values/computed/image.rs +++ b/components/style/values/computed/image.rs @@ -10,10 +10,10 @@ use cssparser::Color as CSSColor; use std::fmt; use style_traits::ToCss; -use url::Url; use values::computed::{Context, Length, LengthOrPercentage, ToComputedValue}; use values::computed::position::Position; -use values::specified::{self, AngleOrCorner, SizeKeyword, UrlExtraData}; +use values::specified::{self, AngleOrCorner, SizeKeyword}; +use values::specified::url::SpecifiedUrl; impl ToComputedValue for specified::Image { @@ -22,8 +22,8 @@ impl ToComputedValue for specified::Image { #[inline] fn to_computed_value(&self, context: &Context) -> Image { match *self { - specified::Image::Url(ref url, ref extra_data) => { - Image::Url(url.clone(), extra_data.clone()) + specified::Image::Url(ref url_value) => { + Image::Url(url_value.clone()) }, specified::Image::Gradient(ref gradient) => { Image::Gradient(gradient.to_computed_value(context)) @@ -34,8 +34,8 @@ impl ToComputedValue for specified::Image { #[inline] fn from_computed_value(computed: &Image) -> Self { match *computed { - Image::Url(ref url, ref extra_data) => { - specified::Image::Url(url.clone(), extra_data.clone()) + Image::Url(ref url_value) => { + specified::Image::Url(url_value.clone()) }, Image::Gradient(ref linear_gradient) => { specified::Image::Gradient( @@ -51,14 +51,14 @@ impl ToComputedValue for specified::Image { #[derive(Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum Image { - Url(Url, UrlExtraData), + Url(SpecifiedUrl), Gradient(Gradient), } impl fmt::Debug for Image { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Image::Url(ref url, ref _extra_data) => write!(f, "url(\"{}\")", url), + Image::Url(ref url) => url.to_css(f), Image::Gradient(ref grad) => { if grad.repeating { let _ = write!(f, "repeating-"); @@ -75,9 +75,7 @@ impl fmt::Debug for Image { impl ToCss for Image { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { - Image::Url(ref url, _) => { - url.to_css(dest) - } + Image::Url(ref url) => url.to_css(dest), Image::Gradient(ref gradient) => gradient.to_css(dest) } } diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index b08c3806ceb..f3524523756 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -12,7 +12,7 @@ use values::{CSSFloat, Either, None_, specified}; pub use cssparser::Color as CSSColor; pub use super::image::{EndingShape as GradientShape, Gradient, GradientKind, Image}; pub use super::image::{LengthOrKeyword, LengthOrPercentageOrKeyword}; -pub use values::specified::{Angle, BorderStyle, Time, UrlExtraData, UrlOrNone}; +pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone}; #[derive(Clone, PartialEq, Copy, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 14e4f49d76c..1e57673d457 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -13,7 +13,8 @@ pub use cssparser::Color as CSSColor; pub use self::image::{EndingShape as GradientShape, Gradient, GradientKind, Image}; pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword}; pub use super::{Either, None_}; -pub use super::specified::{Angle, BorderStyle, Time, UrlExtraData, UrlOrNone}; +pub use super::specified::{Angle, BorderStyle, Time, UrlOrNone}; +pub use super::specified::url::UrlExtraData; pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto}; pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone}; diff --git a/components/style/values/specified/basic_shape.rs b/components/style/values/specified/basic_shape.rs index 6f5bdb03953..88123ea1db1 100644 --- a/components/style/values/specified/basic_shape.rs +++ b/components/style/values/specified/basic_shape.rs @@ -12,12 +12,11 @@ use parser::{Parse, ParserContext}; use properties::shorthands::{parse_four_sides, serialize_four_sides}; use std::fmt; use style_traits::ToCss; -use url::Url; use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue}; use values::computed::basic_shape as computed_basic_shape; use values::specified::{BorderRadiusSize, LengthOrPercentage, Percentage}; -use values::specified::UrlExtraData; use values::specified::position::{Keyword, Position}; +use values::specified::url::SpecifiedUrl; /// A shape source, for some reference box /// @@ -26,7 +25,7 @@ use values::specified::position::{Keyword, Position}; #[derive(Clone, PartialEq, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum ShapeSource<T> { - Url(Url, UrlExtraData), + Url(SpecifiedUrl), Shape(BasicShape, Option<T>), Box(T), None, @@ -41,7 +40,7 @@ impl<T> Default for ShapeSource<T> { impl<T: ToCss> ToCss for ShapeSource<T> { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { - ShapeSource::Url(ref url, _) => url.to_css(dest), + ShapeSource::Url(ref url) => url.to_css(dest), ShapeSource::Shape(ref shape, Some(ref reference)) => { try!(shape.to_css(dest)); try!(dest.write_str(" ")); @@ -59,13 +58,8 @@ impl<T: Parse + PartialEq + Copy> ShapeSource<T> { pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { if let Ok(_) = input.try(|input| input.expect_ident_matching("none")) { Ok(ShapeSource::None) - } else if let Ok(url) = input.try(|input| input.expect_url()) { - match UrlExtraData::make_from(context) { - Some(extra_data) => { - Ok(ShapeSource::Url(context.parse_url(&url), extra_data)) - }, - None => Err(()), - } + } else if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) { + Ok(ShapeSource::Url(url)) } else { fn parse_component<U: Parse>(input: &mut Parser, component: &mut Option<U>) -> bool { if component.is_some() { @@ -98,8 +92,8 @@ impl<T: ToComputedValue> ToComputedValue for ShapeSource<T> { #[inline] fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue { match *self { - ShapeSource::Url(ref url, ref data) => { - computed_basic_shape::ShapeSource::Url(url.clone(), data.clone()) + ShapeSource::Url(ref url) => { + computed_basic_shape::ShapeSource::Url(url.to_computed_value(cx)) } ShapeSource::Shape(ref shape, ref reference) => { computed_basic_shape::ShapeSource::Shape( @@ -116,8 +110,8 @@ impl<T: ToComputedValue> ToComputedValue for ShapeSource<T> { #[inline] fn from_computed_value(computed: &Self::ComputedValue) -> Self { match *computed { - computed_basic_shape::ShapeSource::Url(ref url, ref data) => { - ShapeSource::Url(url.clone(), data.clone()) + computed_basic_shape::ShapeSource::Url(ref url) => { + ShapeSource::Url(SpecifiedUrl::from_computed_value(url)) } computed_basic_shape::ShapeSource::Shape(ref shape, ref reference) => { ShapeSource::Shape( diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs index f6a64ba3c3b..96af3fc91d3 100644 --- a/components/style/values/specified/image.rs +++ b/components/style/values/specified/image.rs @@ -11,49 +11,45 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; use std::f32::consts::PI; use std::fmt; +use std::sync::Arc; use style_traits::ToCss; use url::Url; use values::computed::ComputedValueAsSpecified; -use values::specified::{Angle, CSSColor, Length, LengthOrPercentage, UrlExtraData}; +use values::specified::{Angle, CSSColor, Length, LengthOrPercentage}; use values::specified::position::Position; +use values::specified::url::{SpecifiedUrl, UrlExtraData}; /// Specified values for an image according to CSS-IMAGES. /// https://drafts.csswg.org/css-images/#image-values #[derive(Clone, PartialEq, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum Image { - Url(Url, UrlExtraData), + Url(SpecifiedUrl), Gradient(Gradient), } impl ToCss for Image { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { - Image::Url(ref url, ref _extra_data) => { - url.to_css(dest) - } - Image::Gradient(ref gradient) => gradient.to_css(dest) + Image::Url(ref url_value) => url_value.to_css(dest), + Image::Gradient(ref gradient) => gradient.to_css(dest), } } } impl Image { pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> { - if let Ok(url) = input.try(|input| input.expect_url()) { - match UrlExtraData::make_from(context) { - Some(extra_data) => { - Ok(Image::Url(context.parse_url(&url), extra_data)) - }, - None => { - // FIXME(heycam) should ensure we always have a principal, etc., when - // parsing style attributes and re-parsing due to CSS Variables. - println!("stylo: skipping declaration without ParserContextExtraData"); - Err(()) - }, - } - } else { - Ok(Image::Gradient(try!(Gradient::parse_function(input)))) + if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) { + return Ok(Image::Url(url)); } + + Ok(Image::Gradient(try!(Gradient::parse_function(input)))) + } + + /// Creates an already specified image value from an already resolved URL + /// for insertion in the cascade. + pub fn for_cascade(url: Option<Arc<Url>>, extra_data: UrlExtraData) -> Self { + Image::Url(SpecifiedUrl::for_cascade(url, extra_data)) } } diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 339c565a240..eeed4139cd3 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -5,11 +5,8 @@ use app_units::Au; use cssparser::{self, Parser, Token}; use euclid::size::Size2D; -#[cfg(feature = "gecko")] -use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI}; use parser::ParserContext; -#[cfg(feature = "gecko")] -use parser::ParserContextExtraData; +use self::url::SpecifiedUrl; use std::ascii::AsciiExt; use std::f32::consts::PI; use std::fmt; @@ -17,7 +14,6 @@ use std::ops::Mul; use style_traits::ToCss; use super::{CSSFloat, HasViewportPercentage, NoViewportPercentage}; use super::computed::{ComputedValueAsSpecified, Context, ToComputedValue}; -use url::Url; pub use self::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient}; pub use self::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword}; @@ -30,6 +26,7 @@ pub mod basic_shape; pub mod image; pub mod length; pub mod position; +pub mod url; impl NoViewportPercentage for i32 {} // For PropertyDeclaration::Order @@ -263,42 +260,6 @@ impl Angle { } } -#[derive(PartialEq, Clone, Debug)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub struct UrlExtraData { - #[cfg(feature = "gecko")] - pub base: GeckoArcURI, - #[cfg(feature = "gecko")] - pub referrer: GeckoArcURI, - #[cfg(feature = "gecko")] - pub principal: GeckoArcPrincipal, -} - -impl UrlExtraData { - #[cfg(feature = "servo")] - pub fn make_from(_: &ParserContext) -> Option<UrlExtraData> { - Some(UrlExtraData { }) - } - - #[cfg(feature = "gecko")] - pub fn make_from(context: &ParserContext) -> Option<UrlExtraData> { - match context.extra_data { - ParserContextExtraData { - base: Some(ref base), - referrer: Some(ref referrer), - principal: Some(ref principal), - } => { - Some(UrlExtraData { - base: base.clone(), - referrer: referrer.clone(), - principal: principal.clone(), - }) - }, - _ => None, - } - } -} - pub fn parse_border_radius(input: &mut Parser) -> Result<BorderRadiusSize, ()> { input.try(BorderRadiusSize::parse).or_else(|()| { match_ignore_ascii_case! { try!(input.expect_ident()), @@ -546,7 +507,7 @@ impl ToCss for Opacity { #[derive(PartialEq, Clone, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum UrlOrNone { - Url(Url, UrlExtraData), + Url(SpecifiedUrl), None, } @@ -556,13 +517,8 @@ impl NoViewportPercentage for UrlOrNone {} impl ToCss for UrlOrNone { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { - UrlOrNone::Url(ref url, _) => { - url.to_css(dest) - } - UrlOrNone::None => { - try!(dest.write_str("none")); - Ok(()) - } + UrlOrNone::Url(ref url) => url.to_css(dest), + UrlOrNone::None => dest.write_str("none"), } } } @@ -573,17 +529,6 @@ impl UrlOrNone { return Ok(UrlOrNone::None); } - let url = context.parse_url(&*try!(input.expect_url())); - match UrlExtraData::make_from(context) { - Some(extra_data) => { - Ok(UrlOrNone::Url(url, extra_data)) - }, - _ => { - // FIXME(heycam) should ensure we always have a principal, etc., when parsing - // style attributes and re-parsing due to CSS Variables. - println!("stylo: skipping UrlOrNone declaration without ParserContextExtraData"); - Err(()) - }, - } + Ok(UrlOrNone::Url(try!(SpecifiedUrl::parse(context, input)))) } } diff --git a/components/style/values/specified/url.rs b/components/style/values/specified/url.rs new file mode 100644 index 00000000000..b81c89f887d --- /dev/null +++ b/components/style/values/specified/url.rs @@ -0,0 +1,165 @@ +/* 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/. */ + +//! Common handling for the specified value CSS url() values. + +use cssparser::{CssStringWriter, Parser}; +#[cfg(feature = "gecko")] +use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI}; +use parser::ParserContext; +#[cfg(feature = "gecko")] +use parser::ParserContextExtraData; +use std::fmt::{self, Write}; +use std::ptr; +use std::sync::Arc; +use style_traits::ToCss; +use url::Url; +use values::computed::ComputedValueAsSpecified; + +#[derive(PartialEq, Clone, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct UrlExtraData { + #[cfg(feature = "gecko")] + pub base: GeckoArcURI, + #[cfg(feature = "gecko")] + pub referrer: GeckoArcURI, + #[cfg(feature = "gecko")] + pub principal: GeckoArcPrincipal, +} + +impl UrlExtraData { + #[cfg(feature = "servo")] + pub fn make_from(_: &ParserContext) -> Option<UrlExtraData> { + Some(UrlExtraData { }) + } + + #[cfg(feature = "gecko")] + pub fn make_from(context: &ParserContext) -> Option<UrlExtraData> { + match context.extra_data { + ParserContextExtraData { + base: Some(ref base), + referrer: Some(ref referrer), + principal: Some(ref principal), + } => { + Some(UrlExtraData { + base: base.clone(), + referrer: referrer.clone(), + principal: principal.clone(), + }) + }, + _ => None, + } + } +} + +/// A specified url() value. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct SpecifiedUrl { + /// The original URI. This might be optional since we may insert computed + /// values of images into the cascade directly, and we don't bother to + /// convert their serialization. + /// + /// Refcounted since cloning this should be cheap and data: uris can be + /// really large. + original: Option<Arc<String>>, + + /// The resolved value for the url, if valid. + resolved: Option<Arc<Url>>, + + /// Extra data used for Stylo. + extra_data: UrlExtraData, +} + +impl SpecifiedUrl { + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + let url = try!(input.expect_url()); + + let extra_data = match UrlExtraData::make_from(context) { + Some(extra_data) => extra_data, + None => { + // FIXME(heycam) should ensure we always have a principal, etc., + // when parsing style attributes and re-parsing due to CSS + // Variables. + println!("stylo: skipping declaration without ParserContextExtraData"); + return Err(()) + }, + }; + + let serialization = Arc::new(url.into_owned()); + let resolved = context.base_url.join(&serialization).ok().map(Arc::new); + Ok(SpecifiedUrl { + original: Some(serialization), + resolved: resolved, + extra_data: extra_data, + }) + } + + pub fn extra_data(&self) -> &UrlExtraData { + &self.extra_data + } + + pub fn url(&self) -> Option<&Arc<Url>> { + self.resolved.as_ref() + } + + /// Little helper for Gecko's ffi. + pub fn as_slice_components(&self) -> (*const u8, usize) { + match self.resolved { + Some(ref url) => (url.as_str().as_ptr(), url.as_str().len()), + None => (ptr::null(), 0), + } + } + + /// Creates an already specified url value from an already resolved URL + /// for insertion in the cascade. + pub fn for_cascade(url: Option<Arc<Url>>, extra_data: UrlExtraData) -> Self { + SpecifiedUrl { + original: None, + resolved: url, + extra_data: extra_data, + } + } + + // Just for unit tests, don't use outside of them! + #[cfg(feature = "servo")] + pub fn new_for_testing(url: &str) -> Self { + SpecifiedUrl { + original: Some(Arc::new(url.into())), + resolved: Url::parse(url).ok().map(Arc::new), + extra_data: UrlExtraData {} + } + } +} + +impl PartialEq for SpecifiedUrl { + fn eq(&self, other: &Self) -> bool { + // TODO(emilio): maybe we care about equality of the specified values if + // present? Seems not. + self.resolved == other.resolved && + self.extra_data == other.extra_data + } +} + +impl ToCss for SpecifiedUrl { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(dest.write_str("url(\"")); + let string = match self.original { + Some(ref original) => &**original, + None => match self.resolved { + Some(ref url) => url.as_str(), + // This can only happen if the url wasn't specified by the + // user *and* it's an invalid url that has been transformed + // back to specified value via the "uncompute" functionality. + None => "about:invalid", + } + }; + + try!(CssStringWriter::new(dest).write_str(string)); + dest.write_str("\")") + } +} + +// TODO(emilio): Maybe consider ComputedUrl to save a word in style structs? +impl ComputedValueAsSpecified for SpecifiedUrl {} diff --git a/components/style_traits/Cargo.toml b/components/style_traits/Cargo.toml index 07bc967e664..af4c9314381 100644 --- a/components/style_traits/Cargo.toml +++ b/components/style_traits/Cargo.toml @@ -22,4 +22,3 @@ heapsize_derive = {version = "0.1", optional = true} rustc-serialize = "0.3" serde = {version = "0.8", optional = true} serde_derive = {version = "0.8", optional = true} -url = "1.2" diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs index 4ddb4e6a846..7d8689a0084 100644 --- a/components/style_traits/lib.rs +++ b/components/style_traits/lib.rs @@ -23,7 +23,6 @@ extern crate euclid; extern crate rustc_serialize; #[cfg(feature = "servo")] extern crate serde; #[cfg(feature = "servo")] #[macro_use] extern crate serde_derive; -extern crate url; /// Opaque type stored in type-unsafe work queues for parallel layout. /// Must be transmutable to and from TNode. diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs index 9e8d6b2a936..35c21545ca6 100644 --- a/components/style_traits/values.rs +++ b/components/style_traits/values.rs @@ -3,9 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; -use cssparser::CssStringWriter; -use std::fmt::{self, Write}; -use url::Url; +use std::fmt; /// The real ToCss trait can't be implemented for types in crates that don't /// depend on each other. @@ -30,15 +28,6 @@ impl ToCss for Au { } } -impl ToCss for Url { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(dest.write_str("url(\"")); - try!(write!(CssStringWriter::new(dest), "{}", self)); - try!(dest.write_str("\")")); - Ok(()) - } -} - macro_rules! impl_to_css_for_predefined_type { ($name: ty) => { impl<'a> ToCss for $name { diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 8e94b56ce50..00323809b2e 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -2357,7 +2357,6 @@ dependencies = [ "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/ports/geckolib/Cargo.lock b/ports/geckolib/Cargo.lock index 99e04ca7f95..04d618e46c2 100644 --- a/ports/geckolib/Cargo.lock +++ b/ports/geckolib/Cargo.lock @@ -373,7 +373,6 @@ dependencies = [ "cssparser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs index 3b920059b62..746a45b252e 100644 --- a/tests/unit/style/properties/serialization.rs +++ b/tests/unit/style/properties/serialization.rs @@ -9,9 +9,8 @@ pub use style::values::specified::{BorderStyle, BorderWidth, CSSColor, Length}; pub use style::values::specified::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent}; pub use style::properties::longhands::outline_color::computed_value::T as ComputedColor; pub use style::values::RGBA; -pub use style::values::specified::UrlExtraData; +pub use style::values::specified::url::{UrlExtraData, SpecifiedUrl}; pub use style_traits::ToCss; -pub use url::Url; #[test] fn property_declaration_block_should_serialize_correctly() { @@ -430,9 +429,7 @@ mod shorthand_serialization { let position = DeclaredValue::Value(ListStylePosition::inside); let image = DeclaredValue::Value(ListStyleImage::Url( - Url::parse("http://servo/test.png").unwrap(), - UrlExtraData {}, - )); + SpecifiedUrl::new_for_testing("http://servo/test.png"))); let style_type = DeclaredValue::Value(ListStyleType::disc); properties.push(PropertyDeclaration::ListStylePosition(position)); @@ -747,8 +744,7 @@ mod shorthand_serialization { let attachment = single_vec_keyword_value!(attachment, scroll); let image = single_vec_value!(image, - Some(Image::Url(Url::parse("http://servo/test.png").unwrap(), - UrlExtraData {}))); + Some(Image::Url(SpecifiedUrl::new_for_testing("http://servo/test.png")))); let size = single_vec_variant_value!(size, size::single_value::SpecifiedValue::Explicit( @@ -802,8 +798,7 @@ mod shorthand_serialization { let attachment = single_vec_keyword_value!(attachment, scroll); let image = single_vec_value!(image, - Some(Image::Url(Url::parse("http://servo/test.png").unwrap(), - UrlExtraData {}))); + Some(Image::Url(SpecifiedUrl::new_for_testing("http://servo/test.png")))); let size = single_vec_variant_value!(size, size::single_value::SpecifiedValue::Explicit( @@ -917,8 +912,7 @@ mod shorthand_serialization { let image = single_vec_value_typedef!(image, image::single_value::SpecifiedValue::Image( - Image::Url(Url::parse("http://servo/test.png").unwrap(), - UrlExtraData {}))); + Image::Url(SpecifiedUrl::new_for_testing("http://servo/test.png")))); let mode = single_vec_keyword_value!(mode, luminance); @@ -968,8 +962,7 @@ mod shorthand_serialization { let image = single_vec_value_typedef!(image, image::single_value::SpecifiedValue::Image( - Image::Url(Url::parse("http://servo/test.png").unwrap(), - UrlExtraData {}))); + Image::Url(SpecifiedUrl::new_for_testing("http://servo/test.png")))); let mode = single_vec_keyword_value!(mode, luminance); |