Add SpecifiedImageUrl for <url> used as images. r?emilio
draft
Add SpecifiedImageUrl for <url> used as images. r?emilio
MozReview-Commit-ID: EgRPEcCCx15
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -12,17 +12,17 @@ use app_units::Au;
use gecko::values::{convert_rgba_to_nscolor, GeckoStyleCoordConvertible};
use gecko_bindings::bindings::{Gecko_CreateGradient, Gecko_SetGradientImageValue, Gecko_SetLayerImageImageValue};
use gecko_bindings::bindings::{Gecko_InitializeImageCropRect, Gecko_SetImageElement};
use gecko_bindings::structs::{self, nsCSSUnit, nsStyleCoord_CalcValue};
use gecko_bindings::structs::{nsStyleImage, nsresult, SheetType};
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
use std::f32::consts::PI;
use stylesheets::{Origin, RulesMutateError};
-use values::computed::{Angle, CalcLengthOrPercentage, ComputedUrl, Gradient, Image};
+use values::computed::{Angle, CalcLengthOrPercentage, ComputedImageUrl, Gradient, Image};
use values::computed::{Integer, LengthOrPercentage, LengthOrPercentageOrAuto, Percentage, TextAlign};
use values::generics::box_::VerticalAlign;
use values::generics::grid::{TrackListValue, TrackSize};
use values::generics::image::{CompatMode, Image as GenericImage, GradientItem};
use values::generics::rect::Rect;
impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
@@ -150,22 +150,22 @@ impl nsStyleImage {
/// Set a given Servo `Image` value into this `nsStyleImage`.
pub fn set(&mut self, image: Image) {
match image {
GenericImage::Gradient(boxed_gradient) => {
self.set_gradient(*boxed_gradient)
},
GenericImage::Url(ref url) => {
unsafe {
- Gecko_SetLayerImageImageValue(self, url.image_value.as_ref().unwrap().get());
+ Gecko_SetLayerImageImageValue(self, url.image_value.get());
}
},
GenericImage::Rect(ref image_rect) => {
unsafe {
- Gecko_SetLayerImageImageValue(self, image_rect.url.image_value.as_ref().unwrap().get());
+ Gecko_SetLayerImageImageValue(self, image_rect.url.image_value.get());
Gecko_InitializeImageCropRect(self);
// Set CropRect
let ref mut rect = *self.mCropRect.mPtr;
image_rect.top.to_gecko_style_coord(&mut rect.data_at_mut(0));
image_rect.right.to_gecko_style_coord(&mut rect.data_at_mut(1));
image_rect.bottom.to_gecko_style_coord(&mut rect.data_at_mut(2));
image_rect.left.to_gecko_style_coord(&mut rect.data_at_mut(3));
@@ -414,23 +414,21 @@ impl nsStyleImage {
use gecko_string_cache::Atom;
let atom = Gecko_GetImageElement(self);
Some(GenericImage::Element(Atom::from(atom)))
},
_ => panic!("Unexpected image type")
}
}
- unsafe fn get_image_url(self: &nsStyleImage) -> ComputedUrl {
+ unsafe fn get_image_url(self: &nsStyleImage) -> ComputedImageUrl {
use gecko_bindings::bindings::Gecko_GetURLValue;
let url_value = Gecko_GetURLValue(self);
- let mut url = ComputedUrl::from_url_value_data(url_value.as_ref().unwrap())
- .expect("Could not convert to ComputedUrl");
- url.build_image_value();
- url
+ ComputedImageUrl::from_url_value_data(url_value.as_ref().unwrap())
+ .expect("Could not convert to ComputedUrl")
}
unsafe fn get_gradient(self: &nsStyleImage) -> Box<Gradient> {
use gecko::values::convert_nscolor_to_rgba;
use gecko_bindings::bindings::Gecko_GetGradientImageValue;
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_CIRCULAR, NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL};
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_LINEAR, NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER};
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE};
--- a/servo/components/style/gecko/url.rs
+++ b/servo/components/style/gecko/url.rs
@@ -1,21 +1,23 @@
/* 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::Parser;
+use gecko_bindings::bindings;
use gecko_bindings::structs::{ServoBundledURI, URLExtraData};
use gecko_bindings::structs::mozilla::css::URLValueData;
use gecko_bindings::structs::root::{nsStyleImageRequest, RustString};
use gecko_bindings::structs::root::mozilla::css::ImageValue;
use gecko_bindings::sugar::refptr::RefPtr;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
-use parser::ParserContext;
+use parser::{Parse, ParserContext};
use servo_arc::{Arc, RawOffsetArc};
use std::mem;
use style_traits::ParseError;
/// A specified url() value for gecko. Gecko does not eagerly resolve SpecifiedUrls.
#[css(function = "url")]
#[derive(Clone, Debug, PartialEq, ToCss)]
pub struct SpecifiedUrl {
@@ -23,36 +25,30 @@ pub struct SpecifiedUrl {
///
/// Refcounted since cloning this should be cheap and data: uris can be
/// really large.
serialization: Arc<String>,
/// The URL extra data.
#[css(skip)]
pub extra_data: RefPtr<URLExtraData>,
-
- /// Cache ImageValue, if any, so that we can reuse it while rematching a
- /// a property with this specified url value.
- #[css(skip)]
- pub image_value: Option<RefPtr<ImageValue>>,
}
trivial_to_computed_value!(SpecifiedUrl);
impl SpecifiedUrl {
/// Try to parse a URL from a string value that is a valid CSS token for a
/// URL.
///
/// Returns `Err` in the case that extra_data is incomplete.
pub fn parse_from_string<'a>(url: String,
context: &ParserContext)
-> Result<Self, ParseError<'a>> {
Ok(SpecifiedUrl {
serialization: Arc::new(url),
extra_data: context.url_data.clone(),
- image_value: None,
})
}
/// Returns true if the URL is definitely invalid. We don't eagerly resolve
/// URLs in gecko, so we just return false here.
/// use its |resolved| status.
pub fn is_invalid(&self) -> bool {
false
@@ -66,33 +62,19 @@ impl SpecifiedUrl {
let arc_type = url.mStrings.mRustString.as_ref()
as *const _ as
*const RawOffsetArc<String>;
Arc::from_raw_offset((*arc_type).clone())
} else {
Arc::new(url.mStrings.mString.as_ref().to_string())
},
extra_data: url.mExtraData.to_safe(),
- image_value: None,
})
}
- /// Convert from nsStyleImageRequest to SpecifiedUrl.
- pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Result<SpecifiedUrl, ()> {
- if image_request.mImageValue.mRawPtr.is_null() {
- return Err(());
- }
-
- let image_value = image_request.mImageValue.mRawPtr.as_ref().unwrap();
- let ref url_value_data = image_value._base;
- let mut result = Self::from_url_value_data(url_value_data)?;
- result.build_image_value();
- Ok(result)
- }
-
/// Returns true if this URL looks like a fragment.
/// See https://drafts.csswg.org/css-values/#local-urls
pub fn is_fragment(&self) -> bool {
self.as_str().chars().next().map_or(false, |c| c == '#')
}
/// Return the resolved url as string, or the empty string if it's invalid.
///
@@ -113,46 +95,95 @@ impl SpecifiedUrl {
let arc_offset = Arc::into_raw_offset(self.serialization.clone());
ServoBundledURI {
mURLString: unsafe {
mem::transmute::<_, RawOffsetArc<RustString>>(arc_offset)
},
mExtraData: self.extra_data.get(),
}
}
-
- /// Build and carry an image value on request.
- pub fn build_image_value(&mut self) {
- use gecko_bindings::bindings::Gecko_ImageValue_Create;
-
- debug_assert_eq!(self.image_value, None);
- self.image_value = {
- unsafe {
- let ptr = Gecko_ImageValue_Create(self.for_ffi());
- // We do not expect Gecko_ImageValue_Create returns null.
- debug_assert!(!ptr.is_null());
- Some(RefPtr::from_addrefed(ptr))
- }
- }
- }
}
impl MallocSizeOf for SpecifiedUrl {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
- use gecko_bindings::bindings::Gecko_ImageValue_SizeOfIncludingThis;
-
- let mut n = 0;
-
// XXX: measure `serialization` once bug 1397971 lands
// We ignore `extra_data`, because RefPtr is tricky, and there aren't
// many of them in practise (sharing is common).
- if let Some(ref image_value) = self.image_value {
- // Although this is a RefPtr, this is the primary reference because
- // SpecifiedUrl is responsible for creating the image_value. So we
- // measure unconditionally here.
- n += unsafe { Gecko_ImageValue_SizeOfIncludingThis(image_value.get()) };
+ 0
+ }
+}
+
+/// A specified url() value for image.
+///
+/// This exists so that we can construct `ImageValue` and reuse it.
+#[derive(Clone, Debug, ToCss)]
+pub struct SpecifiedImageUrl {
+ /// The specified url value.
+ pub url: SpecifiedUrl,
+ /// Gecko's ImageValue so that we can reuse it while rematching a
+ /// property with this specified value.
+ #[css(skip)]
+ pub image_value: RefPtr<ImageValue>,
+}
+trivial_to_computed_value!(SpecifiedImageUrl);
+
+impl SpecifiedImageUrl {
+ fn from_specified_url(url: SpecifiedUrl) -> 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,
+ context: &ParserContext
+ ) -> Result<Self, ParseError<'a>> {
+ SpecifiedUrl::parse_from_string(url, context).map(Self::from_specified_url)
+ }
+
+ /// Convert from URLValueData to SpecifiedUrl.
+ pub unsafe fn from_url_value_data(url: &URLValueData) -> Result<Self, ()> {
+ SpecifiedUrl::from_url_value_data(url).map(Self::from_specified_url)
+ }
+
+ /// Convert from nsStyleImageRequest to SpecifiedUrl.
+ pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Result<Self, ()> {
+ 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)
+ }
+}
+
+impl Parse for SpecifiedImageUrl {
+ fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
+ SpecifiedUrl::parse(context, input).map(Self::from_specified_url)
+ }
+}
+
+impl PartialEq for SpecifiedImageUrl {
+ fn eq(&self, other: &Self) -> bool {
+ self.url.eq(&other.url)
+ }
+}
+
+impl Eq for SpecifiedImageUrl {}
+
+impl MallocSizeOf for SpecifiedImageUrl {
+ fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
+ let mut n = self.url.size_of(ops);
+ // Although this is a RefPtr, this is the primary reference because
+ // SpecifiedUrl is responsible for creating the image_value. So we
+ // measure unconditionally here.
+ n += unsafe { bindings::Gecko_ImageValue_SizeOfIncludingThis(self.image_value.get()) };
n
}
}
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -4067,18 +4067,17 @@ fn static_assert() {
match image {
longhands::list_style_image::computed_value::T(Either::Second(_none)) => {
unsafe {
Gecko_SetListStyleImageNone(&mut self.gecko);
}
}
longhands::list_style_image::computed_value::T(Either::First(ref url)) => {
unsafe {
- Gecko_SetListStyleImageImageValue(&mut self.gecko,
- url.image_value.as_ref().unwrap().get());
+ Gecko_SetListStyleImageImageValue(&mut self.gecko, url.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.
}
}
}
@@ -4087,27 +4086,27 @@ fn static_assert() {
unsafe { Gecko_CopyListStyleImageFrom(&mut self.gecko, &other.gecko); }
}
pub fn reset_list_style_image(&mut self, other: &Self) {
self.copy_list_style_image_from(other)
}
pub fn clone_list_style_image(&self) -> longhands::list_style_image::computed_value::T {
- use values::specified::url::SpecifiedUrl;
+ use values::specified::url::SpecifiedImageUrl;
use values::{Either, None_};
longhands::list_style_image::computed_value::T(
match self.gecko.mListStyleImage.mRawPtr.is_null() {
true => Either::Second(None_),
false => {
unsafe {
let ref gecko_image_request = *self.gecko.mListStyleImage.mRawPtr;
- Either::First(SpecifiedUrl::from_image_request(gecko_image_request)
- .expect("mListStyleImage could not convert to SpecifiedUrl"))
+ Either::First(SpecifiedImageUrl::from_image_request(gecko_image_request)
+ .expect("mListStyleImage could not convert to SpecifiedImageUrl"))
}
}
}
)
}
pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T, device: &Device) {
use gecko_bindings::bindings::Gecko_SetCounterStyleToString;
@@ -5285,18 +5284,20 @@ clip-path
CursorKind::MozZoomOut => structs::NS_STYLE_CURSOR_ZOOM_OUT,
} as u8;
unsafe {
Gecko_SetCursorArrayLength(&mut self.gecko, v.images.len());
}
for i in 0..v.images.len() {
unsafe {
- Gecko_SetCursorImageValue(&mut self.gecko.mCursorImages[i],
- v.images[i].url.image_value.as_ref().unwrap().get());
+ Gecko_SetCursorImageValue(
+ &mut self.gecko.mCursorImages[i],
+ v.images[i].url.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 {
@@ -5321,17 +5322,17 @@ clip-path
pub fn reset_cursor(&mut self, other: &Self) {
self.copy_cursor_from(other)
}
pub fn clone_cursor(&self) -> longhands::cursor::computed_value::T {
use values::computed::pointing::CursorImage;
use style_traits::cursor::CursorKind;
- use values::specified::url::SpecifiedUrl;
+ use values::specified::url::SpecifiedImageUrl;
let keyword = match self.gecko.mCursor as u32 {
structs::NS_STYLE_CURSOR_AUTO => CursorKind::Auto,
structs::NS_STYLE_CURSOR_NONE => CursorKind::None,
structs::NS_STYLE_CURSOR_DEFAULT => CursorKind::Default,
structs::NS_STYLE_CURSOR_POINTER => CursorKind::Pointer,
structs::NS_STYLE_CURSOR_CONTEXT_MENU => CursorKind::ContextMenu,
structs::NS_STYLE_CURSOR_HELP => CursorKind::Help,
@@ -5366,18 +5367,18 @@ clip-path
structs::NS_STYLE_CURSOR_ZOOM_IN => CursorKind::ZoomIn,
structs::NS_STYLE_CURSOR_ZOOM_OUT => CursorKind::ZoomOut,
_ => panic!("Found unexpected value in style struct for cursor property"),
};
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();
- SpecifiedUrl::from_image_request(&gecko_image_request)
- .expect("mCursorImages.mImage could not convert to SpecifiedUrl")
+ SpecifiedImageUrl::from_image_request(&gecko_image_request)
+ .expect("mCursorImages.mImage could not convert to SpecifiedImageUrl")
};
let hotspot =
if gecko_cursor_image.mHaveHotspot {
Some((gecko_cursor_image.mHotspotX, gecko_cursor_image.mHotspotY))
} else {
None
};
@@ -5545,18 +5546,20 @@ clip-path
&name,
&sep,
style.clone(),
device,
);
}
ContentItem::Url(ref url) => {
unsafe {
- bindings::Gecko_SetContentDataImageValue(&mut self.gecko.mContents[i],
- url.image_value.as_ref().unwrap().get())
+ bindings::Gecko_SetContentDataImageValue(
+ &mut self.gecko.mContents[i],
+ url.image_value.get(),
+ )
}
}
}
}
}
}
}
@@ -5573,17 +5576,17 @@ clip-path
pub fn clone_content(&self) -> longhands::content::computed_value::T {
use Atom;
use gecko::conversions::string_from_chars_pointer;
use gecko_bindings::structs::nsStyleContentType::*;
use values::computed::counters::{Content, ContentItem};
use values::{CustomIdent, Either};
use values::generics::CounterStyleOrNone;
- use values::specified::url::SpecifiedUrl;
+ use values::specified::url::SpecifiedImageUrl;
use values::specified::Attr;
if self.gecko.mContents.is_empty() {
return Content::Normal;
}
if self.gecko.mContents.len() == 1 &&
self.gecko.mContents[0].mType == eStyleContentType_AltContent {
@@ -5636,18 +5639,18 @@ clip-path
ContentItem::Counters(ident, separator.into_boxed_str(), style)
}
},
eStyleContentType_Image => {
unsafe {
let gecko_image_request =
&**gecko_content.mContent.mImage.as_ref();
ContentItem::Url(
- SpecifiedUrl::from_image_request(gecko_image_request)
- .expect("mContent could not convert to SpecifiedUrl")
+ SpecifiedImageUrl::from_image_request(gecko_image_request)
+ .expect("mContent could not convert to SpecifiedImageUrl")
)
}
},
_ => panic!("Found unexpected value in style struct for content property"),
}
}).collect::<Vec<_>>().into_boxed_slice()
)
}
--- a/servo/components/style/servo/url.rs
+++ b/servo/components/style/servo/url.rs
@@ -158,8 +158,10 @@ impl ToComputedValue for SpecifiedUrl {
ComputedUrl::Invalid(ref url) => SpecifiedUrl {
original: Some(url.clone()),
resolved: None,
}
}
}
}
+/// A specified image url() value for servo.
+pub type SpecifiedImageUrl = SpecifiedUrl;
--- a/servo/components/style/values/computed/counters.rs
+++ b/servo/components/style/values/computed/counters.rs
@@ -13,17 +13,17 @@ use style_traits::{ParseError, StylePars
use values::CustomIdent;
#[cfg(feature = "gecko")]
use values::generics::CounterStyleOrNone;
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::SpecifiedUrl;
+use values::specified::url::SpecifiedImageUrl;
pub use values::specified::{Content, ContentItem};
/// A computed value for the `counter-increment` property.
pub type CounterIncrement = GenericCounterIncrement<i32>;
/// A computed value for the `counter-increment` property.
pub type CounterReset = GenericCounterReset<i32>;
@@ -74,18 +74,17 @@ impl Parse for Content {
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(mut url) = input.try(|i| SpecifiedUrl::parse(_context, i)) {
- url.build_image_value();
+ 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()));
--- a/servo/components/style/values/computed/image.rs
+++ b/servo/components/style/values/computed/image.rs
@@ -7,33 +7,34 @@
//!
//! [image]: https://drafts.csswg.org/css-images/#image-values
use cssparser::RGBA;
use std::f32::consts::PI;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
use values::{Either, None_};
-use values::computed::{Angle, ComputedUrl, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
+use values::computed::{Angle, ComputedImageUrl, Context};
+use values::computed::{Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
#[cfg(feature = "gecko")]
use values::computed::Percentage;
use values::computed::position::Position;
use values::generics::image::{CompatMode, ColorStop as GenericColorStop, EndingShape as GenericEndingShape};
use values::generics::image::{Gradient as GenericGradient, GradientItem as GenericGradientItem};
use values::generics::image::{Image as GenericImage, GradientKind as GenericGradientKind};
use values::generics::image::{LineDirection as GenericLineDirection, MozImageRect as GenericMozImageRect};
use values::specified::image::LineDirection as SpecifiedLineDirection;
use values::specified::position::{X, Y};
/// A computed image layer.
pub type ImageLayer = Either<None_, Image>;
/// Computed values for an image according to CSS-IMAGES.
/// <https://drafts.csswg.org/css-images/#image-values>
-pub type Image = GenericImage<Gradient, MozImageRect, ComputedUrl>;
+pub type Image = GenericImage<Gradient, MozImageRect, ComputedImageUrl>;
/// Computed values for a CSS gradient.
/// <https://drafts.csswg.org/css-images/#gradients>
pub type Gradient = GenericGradient<
LineDirection,
Length,
LengthOrPercentage,
Position,
@@ -71,17 +72,17 @@ pub type EndingShape = GenericEndingShap
/// A computed gradient item.
pub type GradientItem = GenericGradientItem<RGBA, LengthOrPercentage>;
/// A computed color stop.
pub type ColorStop = GenericColorStop<RGBA, LengthOrPercentage>;
/// Computed values for `-moz-image-rect(...)`.
-pub type MozImageRect = GenericMozImageRect<NumberOrPercentage, ComputedUrl>;
+pub type MozImageRect = GenericMozImageRect<NumberOrPercentage, ComputedImageUrl>;
impl GenericLineDirection for LineDirection {
fn points_downwards(&self, compat_mode: CompatMode) -> bool {
match *self {
LineDirection::Angle(angle) => angle.radians() == PI,
LineDirection::Vertical(Y::Bottom)
if compat_mode == CompatMode::Modern => true,
LineDirection::Vertical(Y::Top)
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -641,19 +641,27 @@ impl ClipRectOrAuto {
#[derive(Clone, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
pub enum ComputedUrl {
/// The `url()` was invalid or it wasn't specified by the user.
Invalid(#[ignore_malloc_size_of = "Arc"] Arc<String>),
/// The resolved `url()` relative to the stylesheet URL.
Valid(ServoUrl),
}
-/// TODO: Properly build ComputedUrl for gecko
+/// The computed value of a CSS `url()` for image.
+#[cfg(feature = "servo")]
+pub type ComputedImageUrl = ComputedUrl;
+
+// TODO: Properly build ComputedUrl for gecko
+/// The computed value of a CSS `url()`.
#[cfg(feature = "gecko")]
pub type ComputedUrl = specified::url::SpecifiedUrl;
+/// The computed value of a CSS `url()` for image.
+#[cfg(feature = "gecko")]
+pub type ComputedImageUrl = specified::url::SpecifiedImageUrl;
#[cfg(feature = "servo")]
impl ComputedUrl {
/// Returns the resolved url if it was valid.
pub fn url(&self) -> Option<&ServoUrl> {
match *self {
ComputedUrl::Valid(ref url) => Some(url),
_ => None,
@@ -675,8 +683,11 @@ impl ToCss for ComputedUrl {
dest.write_str("url(")?;
string.to_css(dest)?;
dest.write_str(")")
}
}
/// <url> | <none>
pub type UrlOrNone = Either<ComputedUrl, None_>;
+
+/// <url> | <none> for image
+pub type ImageUrlOrNone = Either<ComputedImageUrl, None_>;
--- a/servo/components/style/values/computed/pointing.rs
+++ b/servo/components/style/values/computed/pointing.rs
@@ -13,17 +13,17 @@ use selectors::parser::SelectorParseErro
use std::fmt::{self, Write};
#[cfg(feature = "gecko")]
use style_traits::{CssWriter, ToCss};
use style_traits::ParseError;
use style_traits::cursor::CursorKind;
use values::computed::color::Color;
use values::generics::pointing::CaretColor as GenericCaretColor;
#[cfg(feature = "gecko")]
-use values::specified::url::SpecifiedUrl;
+use values::specified::url::SpecifiedImageUrl;
/// The computed value for the `cursor` property.
///
/// https://drafts.csswg.org/css-ui/#cursor
pub use values::specified::pointing::Cursor;
#[cfg(feature = "gecko")]
pub use values::specified::pointing::CursorImage;
@@ -60,20 +60,17 @@ impl Parse for Cursor {
#[cfg(feature = "gecko")]
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<Self, ParseError<'i>> {
let mut images = vec![];
loop {
match input.try(|input| CursorImage::parse_image(context, input)) {
- Ok(mut image) => {
- image.url.build_image_value();
- images.push(image)
- }
+ Ok(image) => images.push(image),
Err(_) => break,
}
input.expect_comma()?;
}
Ok(Self {
images: images.into_boxed_slice(),
keyword: CursorKind::parse(context, input)?,
})
@@ -109,17 +106,17 @@ impl Parse for CursorKind {
#[cfg(feature = "gecko")]
impl CursorImage {
fn parse_image<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<Self, ParseError<'i>> {
Ok(Self {
- url: SpecifiedUrl::parse(context, input)?,
+ url: SpecifiedImageUrl::parse(context, input)?,
// FIXME(emilio): Should use Number::parse to handle calc() correctly.
hotspot: match input.try(|input| input.expect_number()) {
Ok(number) => Some((number, input.expect_number()?)),
Err(_) => None,
},
})
}
}
--- a/servo/components/style/values/specified/counters.rs
+++ b/servo/components/style/values/specified/counters.rs
@@ -13,17 +13,17 @@ use values::CustomIdent;
#[cfg(feature = "gecko")]
use values::generics::CounterStyleOrNone;
use values::generics::counters::CounterIncrement as GenericCounterIncrement;
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::SpecifiedUrl;
+use values::specified::url::SpecifiedImageUrl;
/// A specified value for the `counter-increment` property.
pub type CounterIncrement = GenericCounterIncrement<Integer>;
impl Parse for CounterIncrement {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>
@@ -114,10 +114,10 @@ pub enum ContentItem {
NoOpenQuote,
/// `no-close-quote`.
NoCloseQuote,
/// `attr([namespace? `|`]? ident)`
#[cfg(feature = "gecko")]
Attr(Attr),
/// `url(url)`
#[cfg(feature = "gecko")]
- Url(SpecifiedUrl),
+ Url(SpecifiedImageUrl),
}
--- a/servo/components/style/values/specified/image.rs
+++ b/servo/components/style/values/specified/image.rs
@@ -26,24 +26,24 @@ use values::generics::image::{EndingShap
use values::generics::image::{GradientItem as GenericGradientItem, GradientKind as GenericGradientKind};
use values::generics::image::{Image as GenericImage, LineDirection as GenericsLineDirection};
use values::generics::image::{MozImageRect as GenericMozImageRect, ShapeExtent};
use values::generics::image::PaintWorklet;
use values::generics::position::Position as GenericPosition;
use values::specified::{Angle, Color, Length, LengthOrPercentage};
use values::specified::{Number, NumberOrPercentage, Percentage, RGBAColor};
use values::specified::position::{LegacyPosition, Position, PositionComponent, Side, X, Y};
-use values::specified::url::SpecifiedUrl;
+use values::specified::url::SpecifiedImageUrl;
/// A specified image layer.
pub type ImageLayer = Either<None_, Image>;
/// Specified values for an image according to CSS-IMAGES.
/// <https://drafts.csswg.org/css-images/#image-values>
-pub type Image = GenericImage<Gradient, MozImageRect, SpecifiedUrl>;
+pub type Image = GenericImage<Gradient, MozImageRect, SpecifiedImageUrl>;
/// Specified values for a CSS gradient.
/// <https://drafts.csswg.org/css-images/#gradients>
#[cfg(not(feature = "gecko"))]
pub type Gradient = GenericGradient<
LineDirection,
Length,
LengthOrPercentage,
@@ -119,42 +119,33 @@ pub type EndingShape = GenericEndingShap
/// A specified gradient item.
pub type GradientItem = GenericGradientItem<RGBAColor, LengthOrPercentage>;
/// A computed color stop.
pub type ColorStop = GenericColorStop<RGBAColor, LengthOrPercentage>;
/// Specified values for `moz-image-rect`
/// -moz-image-rect(<uri>, top, right, bottom, left);
-pub type MozImageRect = GenericMozImageRect<NumberOrPercentage, SpecifiedUrl>;
+pub type MozImageRect = GenericMozImageRect<NumberOrPercentage, SpecifiedImageUrl>;
impl Parse for Image {
- #[cfg_attr(not(feature = "gecko"), allow(unused_mut))]
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Image, ParseError<'i>> {
- if let Ok(mut url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
- #[cfg(feature = "gecko")]
- {
- url.build_image_value();
- }
+ if let Ok(url) = input.try(|input| SpecifiedImageUrl::parse(context, input)) {
return Ok(GenericImage::Url(url));
}
if let Ok(gradient) = input.try(|i| Gradient::parse(context, i)) {
return Ok(GenericImage::Gradient(Box::new(gradient)));
}
#[cfg(feature = "servo")]
{
if let Ok(paint_worklet) = input.try(|i| PaintWorklet::parse(context, i)) {
return Ok(GenericImage::PaintWorklet(paint_worklet));
}
}
- if let Ok(mut image_rect) = input.try(|input| MozImageRect::parse(context, input)) {
- #[cfg(feature = "gecko")]
- {
- image_rect.url.build_image_value();
- }
+ if let Ok(image_rect) = input.try(|input| MozImageRect::parse(context, input)) {
return Ok(GenericImage::Rect(Box::new(image_rect)));
}
Ok(GenericImage::Element(Image::parse_element(input)?))
}
}
impl Image {
/// Creates an already specified image value from an already resolved URL
@@ -939,28 +930,21 @@ impl Parse for PaintWorklet {
}
}
impl Parse for MozImageRect {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.try(|i| i.expect_function_matching("-moz-image-rect"))?;
input.parse_nested_block(|i| {
let string = i.expect_url_or_string()?;
- let url = SpecifiedUrl::parse_from_string(string.as_ref().to_owned(), context)?;
+ let url = SpecifiedImageUrl::parse_from_string(string.as_ref().to_owned(), context)?;
i.expect_comma()?;
let top = NumberOrPercentage::parse_non_negative(context, i)?;
i.expect_comma()?;
let right = NumberOrPercentage::parse_non_negative(context, i)?;
i.expect_comma()?;
let bottom = NumberOrPercentage::parse_non_negative(context, i)?;
i.expect_comma()?;
let left = NumberOrPercentage::parse_non_negative(context, i)?;
-
- Ok(MozImageRect {
- url: url,
- top: top,
- right: right,
- bottom: bottom,
- left: left,
- })
+ Ok(MozImageRect { url, top, right, bottom, left })
})
}
}
--- a/servo/components/style/values/specified/list.rs
+++ b/servo/components/style/values/specified/list.rs
@@ -8,17 +8,17 @@ use cssparser::{Parser, Token};
use parser::{Parse, ParserContext};
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use values::{Either, None_};
#[cfg(feature = "gecko")]
use values::CustomIdent;
#[cfg(feature = "gecko")]
use values::generics::CounterStyleOrNone;
-use values::specified::UrlOrNone;
+use values::specified::ImageUrlOrNone;
/// Specified and computed `list-style-type` property.
#[cfg(feature = "gecko")]
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
pub enum ListStyleType {
/// <counter-style> | none
CounterStyle(CounterStyleOrNone),
/// <string>
@@ -70,44 +70,36 @@ impl Parse for ListStyleType {
}
Ok(ListStyleType::String(input.expect_string()?.as_ref().to_owned()))
}
}
/// Specified and computed `list-style-image` property.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
-pub struct ListStyleImage(pub UrlOrNone);
+pub struct ListStyleImage(pub ImageUrlOrNone);
// FIXME(nox): This is wrong, there are different types for specified
// and computed URLs in Servo.
trivial_to_computed_value!(ListStyleImage);
impl ListStyleImage {
/// Initial specified value for `list-style-image`.
#[inline]
pub fn none() -> ListStyleImage {
ListStyleImage(Either::Second(None_))
}
}
impl Parse for ListStyleImage {
- fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
- -> Result<ListStyleImage, ParseError<'i>> {
- #[allow(unused_mut)]
- let mut value = input.try(|input| UrlOrNone::parse(context, input))?;
-
- #[cfg(feature = "gecko")]
- {
- if let Either::First(ref mut url) = value {
- url.build_image_value();
- }
- }
-
- return Ok(ListStyleImage(value));
+ fn parse<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<ListStyleImage, ParseError<'i>> {
+ ImageUrlOrNone::parse(context, input).map(ListStyleImage)
}
}
/// Specified and computed `quote` property.
///
/// FIXME(emilio): It's a shame that this allocates all the time it's computed,
/// probably should just be refcounted.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -6,17 +6,17 @@
//!
//! TODO(emilio): Enhance docs.
use Prefix;
use context::QuirksMode;
use cssparser::{Parser, Token, serialize_identifier};
use num_traits::One;
use parser::{ParserContext, Parse};
-use self::url::SpecifiedUrl;
+use self::url::{SpecifiedImageUrl, SpecifiedUrl};
use std::f32;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use style_traits::values::specified::AllowedNumericType;
use super::{Auto, CSSFloat, CSSInteger, Either, None_};
use super::computed::{Context, ToComputedValue};
use super::generics::{GreaterThanOrEqualToOne, NonNegative};
use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
@@ -529,16 +529,19 @@ impl Parse for PositiveInteger {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Integer::parse_positive(context, input).map(GreaterThanOrEqualToOne::<Integer>)
}
}
#[allow(missing_docs)]
pub type UrlOrNone = Either<SpecifiedUrl, None_>;
+/// The specified value of a `<url>` for image or `none`.
+pub type ImageUrlOrNone = Either<SpecifiedImageUrl, None_>;
+
/// The specified value of a grid `<track-breadth>`
pub type TrackBreadth = GenericTrackBreadth<LengthOrPercentage>;
/// The specified value of a grid `<track-size>`
pub type TrackSize = GenericTrackSize<LengthOrPercentage>;
/// The specified value of a grid `<track-list>`
/// (could also be `<auto-track-list>` or `<explicit-track-list>`)
--- a/servo/components/style/values/specified/pointing.rs
+++ b/servo/components/style/values/specified/pointing.rs
@@ -8,17 +8,17 @@
use cssparser::Parser;
use parser::{Parse, ParserContext};
use style_traits::ParseError;
use style_traits::cursor::CursorKind;
use values::generics::pointing::CaretColor as GenericCaretColor;
use values::specified::color::Color;
#[cfg(feature = "gecko")]
-use values::specified::url::SpecifiedUrl;
+use values::specified::url::SpecifiedImageUrl;
/// The specified value for the `cursor` property.
///
/// https://drafts.csswg.org/css-ui/#cursor
#[cfg(feature = "servo")]
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
pub struct Cursor(pub CursorKind);
@@ -34,17 +34,17 @@ pub struct Cursor {
pub keyword: CursorKind,
}
/// The specified value for the `image cursors`.
#[cfg(feature = "gecko")]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
pub struct CursorImage {
/// The url to parse images from.
- pub url: SpecifiedUrl,
+ pub url: SpecifiedImageUrl,
/// The <x> and <y> coordinates.
pub hotspot: Option<(f32, f32)>,
}
/// A specified value for the `caret-color` property.
pub type CaretColor = GenericCaretColor<Color>;
impl Parse for CaretColor {
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -3539,29 +3539,28 @@ pub extern "C" fn Servo_DeclarationBlock
declarations: RawServoDeclarationBlockBorrowed,
value: *const nsAString,
raw_extra_data: *mut URLExtraData,
) {
use style::properties::PropertyDeclaration;
use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
use style::values::Either;
use style::values::generics::image::Image;
- use style::values::specified::url::SpecifiedUrl;
+ use style::values::specified::url::SpecifiedImageUrl;
let url_data = unsafe { RefPtr::from_ptr_ref(&raw_extra_data) };
let string = unsafe { (*value).to_string() };
let context = ParserContext::new(
Origin::Author,
url_data,
Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
);
- if let Ok(mut url) = SpecifiedUrl::parse_from_string(string.into(), &context) {
- url.build_image_value();
+ if let Ok(url) = SpecifiedImageUrl::parse_from_string(string.into(), &context) {
let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(
vec![Either::Second(Image::Url(url))]
));
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(decl, Importance::Normal, DeclarationSource::CssOm);
})
}
}